DIGILIGHT
mmc.c
1 /*-------------------------------------------------------------------------*/
2 /* PFF - Low level disk control module for AVR (C)ChaN, 2010 */
3 /*-------------------------------------------------------------------------*/
4 
5 #include "pff.h"
6 #include "diskio.h"
7 
8 /*-------------------------------------------------------------------------*/
9 /* Platform dependent macros and functions needed to be modified */
10 /*-------------------------------------------------------------------------*/
11 
12 #include <avr/io.h> /* Device include file */
13 #include "spi.h"
14 
15 #define SELECT() SPI_EnableSS_m(SPI_SS) /* CS = L */
16 #define DESELECT() SPI_DisableSS_m(SPI_SS) /* CS = H */
17 #define MMC_SEL SPI_StatSS_m(SPI_SS) /* CS status (true:CS == L) */
18 #define FORWARD(d) /* Data forwarding function (Console out in this example) */
19 
20 #define init_spi() SPI_Init() /* Initialize SPI port (usi.S) */
21 #define dly_100us() _delay_us(100) /* Delay 100 microseconds (usi.S) */
22 #define xmit_spi(d) SPI_WriteByte_m(d) /* Send a byte to the MMC (usi.S) */
23 #define rcv_spi() SPI_ReadByte_i() /* Send a 0xFF to the MMC and get the received byte (usi.S) */
24 
25 
26 
27 /*--------------------------------------------------------------------------
28 
29  Module Private Functions
30 
31 ---------------------------------------------------------------------------*/
32 
33 /* Definitions for MMC/SDC command */
34 #define CMD0 (0x40+0) /* GO_IDLE_STATE */
35 #define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
36 #define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
37 #define CMD8 (0x40+8) /* SEND_IF_COND */
38 #define CMD16 (0x40+16) /* SET_BLOCKLEN */
39 #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
40 #define CMD24 (0x40+24) /* WRITE_BLOCK */
41 #define CMD55 (0x40+55) /* APP_CMD */
42 #define CMD58 (0x40+58) /* READ_OCR */
43 
44 
45 /* Card type flags (CardType) */
46 #define CT_MMC 0x01 /* MMC ver 3 */
47 #define CT_SD1 0x02 /* SD ver 1 */
48 #define CT_SD2 0x04 /* SD ver 2 */
49 #define CT_BLOCK 0x08 /* Block addressing */
50 
51 
52 static
53 BYTE CardType;
54 
55 
56 /*-----------------------------------------------------------------------*/
57 /* Send a command packet to MMC */
58 /*-----------------------------------------------------------------------*/
59 
60 static
61 BYTE send_cmd (
62  BYTE cmd, /* 1st byte (Start + Index) */
63  DWORD arg /* Argument (32 bits) */
64 )
65 {
66  BYTE n, res;
67 
68 
69  if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
70  cmd &= 0x7F;
71  res = send_cmd(CMD55, 0);
72  if (res > 1) return res;
73  }
74 
75  /* Select the card */
76  DESELECT();
77  rcv_spi();
78  SELECT();
79  rcv_spi();
80 
81  /* Send a command packet */
82  xmit_spi(cmd); /* Start + Command index */
83  xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
84  xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
85  xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
86  xmit_spi((BYTE)arg); /* Argument[7..0] */
87  n = 0x01; /* Dummy CRC + Stop */
88  if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
89  if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
90  xmit_spi(n);
91 
92  /* Receive a command response */
93  n = 10; /* Wait for a valid response in timeout of 10 attempts */
94  do {
95  res = rcv_spi();
96  } while ((res & 0x80) && --n);
97 
98  return res; /* Return with the response value */
99 }
100 
101 
102 
103 
104 /*--------------------------------------------------------------------------
105 
106  Public Functions
107 
108 ---------------------------------------------------------------------------*/
109 
110 /*-----------------------------------------------------------------------*/
111 /* Initialize Disk Drive */
112 /*-----------------------------------------------------------------------*/
113 
114 DSTATUS disk_initialize (void)
115 {
116  BYTE n, cmd, ty, ocr[4];
117  UINT tmr;
118 
119 #if _USE_WRITE
120  if (CardType && MMC_SEL) disk_writep(0, 0); /* Finalize write process if it is in progress */
121 #endif
122  //init_spi(); /* Initialize ports to control MMC */
123  DESELECT();
124  for (n = 10; n; n--){
125  rcv_spi(); /* 80 dummy clocks with CS=H */
126  }
127 
128  ty = 0;
129  if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
130  if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */
131  for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); /* Get trailing return value of R7 resp */
132  if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
133  for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /* Wait for leaving idle state (ACMD41 with HCS bit) */
134  if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
135  for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
136  ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
137  }
138  }
139  } else { /* SDv1 or MMCv3 */
140  if (send_cmd(ACMD41, 0) <= 1) {
141  ty = CT_SD1; cmd = ACMD41; /* SDv1 */
142  } else {
143  ty = CT_MMC; cmd = CMD1; /* MMCv3 */
144  }
145  for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /* Wait for leaving idle state */
146  if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
147  ty = 0;
148  }
149  }
150  CardType = ty;
151  DESELECT();
152  rcv_spi();
153 
154  return ty ? 0 : STA_NOINIT;
155 }
156 
157 
158 
159 /*-----------------------------------------------------------------------*/
160 /* Read partial sector */
161 /*-----------------------------------------------------------------------*/
162 
163 DRESULT disk_readp (
164  BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
165  DWORD lba, /* Sector number (LBA) */
166  UINT ofs, /* Byte offset to read from (0..511) */
167  UINT cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */
168 )
169 {
170  DRESULT res;
171  BYTE rc;
172  WORD bc;
173 
174 
175  if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */
176 
177  res = RES_ERROR;
178  if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */
179 
180  bc = 40000;
181  do { /* Wait for data packet */
182  rc = rcv_spi();
183  } while (rc == 0xFF && --bc);
184 
185  if (rc == 0xFE) { /* A data packet arrived */
186  bc = 514 - ofs - cnt;
187 
188  /* Skip leading bytes */
189  if (ofs) {
190  do rcv_spi(); while (--ofs);
191  }
192 
193  /* Receive a part of the sector */
194  if (buff) { /* Store data to the memory */
195  do {
196  *buff++ = rcv_spi();
197  } while (--cnt);
198  } else { /* Forward data to the outgoing stream (depends on the project) */
199  do {
200  FORWARD(rcv_spi());
201  } while (--cnt);
202  }
203 
204  /* Skip trailing bytes and CRC */
205  do rcv_spi(); while (--bc);
206 
207  res = RES_OK;
208  }
209  }
210 
211  DESELECT();
212  rcv_spi();
213 
214  return res;
215 }
216 
217 
218 
219 /*-----------------------------------------------------------------------*/
220 /* Write partial sector */
221 /*-----------------------------------------------------------------------*/
222 
223 #if _USE_WRITE
224 DRESULT disk_writep (
225  const BYTE *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
226  DWORD sa /* Number of bytes to send, Sector number (LBA) or zero */
227 )
228 {
229  DRESULT res;
230  WORD bc;
231  static WORD wc;
232 
233  res = RES_ERROR;
234 
235  if (buff) { /* Send data bytes */
236  bc = (WORD)sa;
237  while (bc && wc) { /* Send data bytes to the card */
238  xmit_spi(*buff++);
239  wc--; bc--;
240  }
241  res = RES_OK;
242  } else {
243  if (sa) { /* Initiate sector write process */
244  if (!(CardType & CT_BLOCK)) sa *= 512; /* Convert to byte address if needed */
245  if (send_cmd(CMD24, sa) == 0) { /* WRITE_SINGLE_BLOCK */
246  xmit_spi(0xFF); xmit_spi(0xFE); /* Data block header */
247  wc = 512; /* Set byte counter */
248  res = RES_OK;
249  }
250  } else { /* Finalize sector write process */
251  bc = wc + 2;
252  while (bc--) xmit_spi(0); /* Fill left bytes and CRC with zeros */
253  if ((rcv_spi() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 500ms */
254  for (bc = 5000; rcv_spi() != 0xFF && bc; bc--) dly_100us(); /* Wait ready */
255  if (bc) res = RES_OK;
256  }
257  DESELECT();
258  rcv_spi();
259  }
260  }
261 
262  return res;
263 }
264 #endif