-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmmcbb.c
More file actions
438 lines (340 loc) · 11.6 KB
/
mmcbb.c
File metadata and controls
438 lines (340 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/*------------------------------------------------------------------------/
/ Bitbanging MMCv3/SDv1/SDv2 (in SPI mode) control module for PFF
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2010, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/--------------------------------------------------------------------------/
Features:
* Very Easy to Port
It uses only 4-6 bit of GPIO port. No interrupt, no SPI port is used.
* Platform Independent
You need to modify only a few macros to control GPIO ports.
/-------------------------------------------------------------------------*/
//PETIT FAT stuff
#include "diskio.h"
//include byte rx tx functions via SPI or UART
#include "USCI.h"
//include delay function
#include "CHandler.h"
//MSP430 port defs
#include "msp430.h"
/*-------------------------------------------------------------------------*/
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
//#include <hardware.h> /* Include hardware specific declareation file here */
#define INIT_PORT() /* Initialize MMC control port (CS/CLK/DI:output, DO:input) */
#define DLY_US(n) delay_us(n) /* Delay n microseconds */
#define FORWARD(d) USCI_A_uartSend(d) /* Data in-time processing function (depends on the project) */
#define CS_H() P1OUT |= (1 << SD_CARD)
#define CS_L() P1OUT &= ~(1 << SD_CARD)
//#define DEBUG
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
/* Card type flags (CardType) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
static
BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
/*-----------------------------------------------------------------------*/
/* Transmit a byte to the MMC (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void xmit_mmc (
BYTE d /* Data to be sent */
)
{
USCI_B_spiXmit(d);
}
/*-----------------------------------------------------------------------*/
/* Receive a byte from the MMC (bitbanging) */
/*-----------------------------------------------------------------------*/
static
BYTE rcvr_mmc (void)
{
return USCI_B_spiXmit(0xff);
}
/*-----------------------------------------------------------------------*/
/* Skip bytes on the MMC (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void skip_mmc (
WORD n /* Number of bytes to skip */
)
{
do {
USCI_B_spiXmit(0xff);
} while (--n);
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void release_spi (void)
{
CS_H();
rcvr_mmc();
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd (
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, res;
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
res = send_cmd(CMD55, 0);
if (res > 1) return res;
}
/* Select the card */
CS_H(); rcvr_mmc();
CS_L(); rcvr_mmc();
/* Send a command packet */
xmit_mmc(cmd); /* Start + Command index */
xmit_mmc((BYTE)(arg >> 24)); /* Argument[31..24] */
xmit_mmc((BYTE)(arg >> 16)); /* Argument[23..16] */
xmit_mmc((BYTE)(arg >> 8)); /* Argument[15..8] */
xmit_mmc((BYTE)arg); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xmit_mmc(n);
/* Receive a command response */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do {
res = rcvr_mmc();
} while ((res & 0x80) && --n);
return res; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (void)
{
BYTE n, cmd, ty, buf[4];
UINT tmr;
CS_H();
skip_mmc(10); /* Dummy clocks */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */
for (n = 0; n < 4; n++) buf[n] = rcvr_mmc(); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (send_cmd(ACMD41, 1UL << 30) == 0) break;
DLY_US(1000);
}
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
for (n = 0; n < 4; n++) buf[n] = rcvr_mmc();
ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
}
}
} else { /* SDv1 or MMCv3 */
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
}
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
if (send_cmd(cmd, 0) == 0) break;
DLY_US(1000);
}
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
release_spi();
return ty ? 0 : STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read partial sector */
/*-----------------------------------------------------------------------*/
DRESULT disk_readp (
BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
DWORD lba, /* Sector number (LBA) */
WORD ofs, /* Byte offset to read from (0..511) */
WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */
)
{
DRESULT res;
BYTE d;
WORD bc, tmr;
if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */
res = RES_ERROR;
if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */
tmr = 1000;
do { /* Wait for data packet in timeout of 100ms */
DLY_US(100);
d = rcvr_mmc();
} while (d == 0xFF && --tmr);
if (d == 0xFE) { /* A data packet arrived */
bc = 514 - ofs - cnt;
/* Skip leading bytes */
if (ofs) skip_mmc(ofs);
/* Receive a part of the sector */
if (buff) { /* Store data to the memory */
do
*buff++ = rcvr_mmc();
while (--cnt);
} else { /* Forward data to the outgoing stream */
do {
d = rcvr_mmc();
FORWARD(d);
} while (--cnt);
}
/* Skip trailing bytes and CRC */
skip_mmc(bc);
res = RES_OK;
}
}
release_spi();
return res;
}
/*-----------------------------------------------------------------------*/
/* Write partial sector */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_writep (
const BYTE *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
DWORD sa /* Number of bytes to send, Sector number (LBA) or zero */
)
{
DRESULT res;
WORD bc, tmr;
static WORD wc;
res = RES_ERROR;
if (buff) { /* Send data bytes */
bc = (WORD)sa;
while (bc && wc) { /* Send data bytes to the card */
xmit_mmc(*buff++);
wc--; bc--;
}
res = RES_OK;
} else {
if (sa) { /* Initiate sector write process */
if (!(CardType & CT_BLOCK)) sa *= 512; /* Convert to byte address if needed */
if (send_cmd(CMD24, sa) == 0) { /* WRITE_SINGLE_BLOCK */
xmit_mmc(0xFF); xmit_mmc(0xFE); /* Data block header */
wc = 512; /* Set byte counter */
res = RES_OK;
}
} else { /* Finalize sector write process */
bc = wc + 2;
while (bc--) xmit_mmc(0); /* Fill left bytes and CRC with zeros */
if ((rcvr_mmc() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 300ms */
for (tmr = 10000; rcvr_mmc() != 0xFF && tmr; tmr--) /* Wait for ready (max 1000ms) */
DLY_US(100);
if (tmr) res = RES_OK;
}
release_spi();
}
}
return res;
}
#endif
/*
* TEST Code
*/
#ifdef DEBUG
uint16_t testSDCard(void) {
FATFS fatfs; /* File system object */
DIR dir; /* Directory object */
FILINFO fno; /* File information object */
WORD bw, br, i;
BYTE buff[64];
print("Mount a volume.");
RET();
FRESULT rc = pf_mount(&fatfs);
if (rc) die(rc);
print("Open a test file (message.txt).");
RET();
rc = pf_open("MESSAGE.TXT");
if (rc) die(rc);
print("Type the file content.");
RET();
for (;;) {
rc = pf_read(buff, sizeof(buff), &br); /* Read a chunk of file */
if (rc || !br) break; /* Error or end of file */
for (i = 0; i < br; i++) /* Type the data */
putchar(buff[i]);
}
if (rc) die(rc);
#if _USE_WRITE
sprintf(string,"\nOpen a file to write (write.txt).\n");
print(string);
rc = pf_open("WRITE.TXT");
if (rc) die(rc);
sprintf(string,"\nWrite a text data. (Hello world!)\n");
print(string);
for (;;) {
rc = pf_write("Hello world!\r\n", 14, &bw);
if (rc || !bw) break;
}
if (rc) die(rc);
sprintf(string,"\nTerminate the file write process.\n");
print(string);
rc = pf_write(0, 0, &bw);
if (rc) die(rc);
#endif
#if _USE_DIR
print("Open root directory.");
RET();
rc = pf_opendir(&dir, "");
if (rc) die(rc);
print("Directory listing...");
RET();
for (;;) {
rc = pf_readdir(&dir, &fno); /* Read a directory item */
if (rc || !fno.fname[0]) break; /* Error or end of dir */
if (fno.fattrib & AM_DIR)
{
print(" <dir> ");
print(fno.fname);
RET();
}
else
{
printInt((uint8_t*)&fno.fsize, sizeof(fno.fsize));
print(fno.fname);
RET();
}
}
if (rc) die(rc);
#endif
print("\nTest completed.\n");
while(1)
{
delay_ten_us(50000);
delay_ten_us(50000);
P1OUT ^= (1 << RED_LED);
}
return 0xaa55;
}
#endif