1 /*****************************************************************************\
2 * efs - General purpose Embedded Filesystem library *
3 * --------------------- ----------------------------------- *
6 * Revision : Initial developement *
7 * Description : This file contains the functions needed to use efs for *
8 * accessing files on an SD-card. *
10 * This library is free software; you can redistribute it and/or *
11 * modify it under the terms of the GNU Lesser General Public *
12 * License as published by the Free Software Foundation; either *
13 * version 2.1 of the License, or (at your option) any later version. *
15 * This library is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
18 * Lesser General Public License for more details. *
20 * (c)2005 Michael De Nil *
21 * (c)2005 Lennart Yseboodt *
22 \*****************************************************************************/
25 2006, Bertrik Sikken, modified for LPCUSB
32 #include "../fatfs/diskio.h"
33 #include "../fatfs/ff.h"
34 #include "../fatfs/mmc.h"
35 #include "../fatfs/spi.h"
43 #define CMD_GOIDLESTATE 0
44 #define CMD_SENDOPCOND 1
46 #define CMD_READCID 10
47 #define CMD_SENDSTATUS 13
48 #define CMD_READSINGLEBLOCK 17
50 #define CMD_WRITE_MULTIPLE 25
55 static void mscblockCommand (U8 cmd, U32 param)
60 abCmd [1] = 0x40 | cmd;
61 abCmd [2] = (U8)(param >> 24);
62 abCmd [3] = (U8)(param >> 16);
63 abCmd [4] = (U8)(param >> 8);
64 abCmd [5] = (U8)(param);
65 abCmd [6] = 0x95; /* Checksum (should be only valid for first command (0) */
66 abCmd [7] = 0xff; /* eat empty command - response */
68 mscspiSendBlock (abCmd, 8);
74 static U8 mscblockResp8b (void)
79 /* Respone will come after 1 - 8 pings */
80 for (i = 0; i < 8; i++)
81 if ((resp = mscspiTransferByte (0xff)) != 0xff)
90 static void mscblockResp8bError (U8 value)
94 case 0x40 : DBG ("Argument out of bounds.\n"); break;
95 case 0x20 : DBG ("Address out of bounds.\n"); break;
96 case 0x10 : DBG ("Error during erase sequence.\n"); break;
97 case 0x08 : DBG ("CRC failed.\n"); break;
98 case 0x04 : DBG ("Illegal command.\n"); break;
99 case 0x02 : DBG ("Erase reset (see SanDisk docs p5-13).\n"); break;
100 case 0x01 : DBG ("Card is initialising.\n"); break;
101 default : DBG ("Unknown error 0x%x (see SanDisk docs p5-13).\n", value); break;
106 // Calculates size of card from CSD
107 // (extension by Martin Thomas, inspired by code from Holger Klabunde)
109 int mscblockGetSize (U32 *pdwDriveSize)
113 U16 c_size, c_size_mult, read_bl_len;
115 mscblockCommand (CMD_READCSD, 0);
118 cardresp = mscblockResp8b ();
120 while (cardresp != 0xfe);
124 for (i = 0; i < 16; i++)
126 iob [i] = mscspiTransferByte (0xff);
127 DBG (" %02x", iob [i]);
132 mscspiTransferByte (0xff);
133 mscspiTransferByte (0xff);
135 c_size = iob [6] & 0x03;
137 c_size += (U16) iob [7] << 2;
138 c_size += iob [8] >> 6;
141 read_bl_len = 1 << by;
147 c_size_mult = 1 << (2 + by);
149 *pdwDriveSize = (U32) (c_size + 1) * (U32) c_size_mult * (U32) read_bl_len;
157 static U16 mscblockResp16b (void)
161 resp = (mscblockResp8b() << 8) & 0xff00;
162 resp |= mscspiTransferByte(0xff);
170 static int mscblockState (void)
174 mscblockCommand (CMD_SENDSTATUS, 0);
175 value = mscblockResp16b ();
179 case 0x0000 : return 1;
180 case 0x0001 : DBG ("Card is Locked.\n"); break;
181 case 0x0002 : DBG ("WP Erase Skip, Lock/Unlock Cmd Failed.\n"); break;
182 case 0x0004 : DBG ("General / Unknown error -- card broken?.\n"); break;
183 case 0x0008 : DBG ("Internal card controller error.\n"); break;
184 case 0x0010 : DBG ("Card internal ECC was applied, but failed to correct the data.\n"); break;
185 case 0x0020 : DBG ("Write protect violation.\n"); break;
186 case 0x0040 : DBG ("An invalid selection, sectors for erase.\n"); break;
187 case 0x0080 : DBG ("Out of Range, CSD_Overwrite.\n"); break;
188 default : if (value > 0x00ff)
189 mscblockResp8bError ((U8) (value >> 8));
191 DBG ("Unknown error: 0x%x (see SanDisk docs p5-14).\n", value);
201 int mscblockInit (void)
206 // We'll see the error because it means we *must* be using a serial
207 // console, since we can't use USB for MSC and VCOM at the same time.
212 if ((f = diskInitialize (0)) != FR_OK)
221 // Try to send reset command up to 100 times
227 mscblockCommand (CMD_GOIDLESTATE, 0);
228 resp = mscblockResp8b ();
230 while (resp != 1 && i--);
241 mscblockResp8bError (resp);
242 DBG ("resp!=0xff\n");
248 // Wait till card is ready initialising (returns 0 on CMD_1)
249 // Try up to 32000 times. */
255 mscblockCommand (CMD_SENDOPCOND, 0);
257 if ((resp = mscblockResp8b ()) != 0)
258 mscblockResp8bError (resp);
260 while (resp == 1 && i--);
264 mscblockResp8bError (resp);
269 // Increase speed after init
271 // mscspiSetSpeed (SPI_PRESCALE_MIN);
274 if (mscblockState () < 0)
276 DBG ("Card didn't return the ready state, breaking up...\n");
280 DBG ("Init done...\n");
297 int mscblockWrite (U32 dwAddress, U8 * pbBuf)
302 place = 512 * dwAddress;
303 mscblockCommand (CMD_WRITE, place);
305 mscblockResp8b (); /* Card response */
307 mscspiTransferByte (0xfe); /* Start block */
308 mscspiSendBlock (pbBuf, 512);
309 mscspiTransferByte (0xff); /* Checksum part 1 */
310 mscspiTransferByte (0xff); /* Checksum part 2 */
312 mscspiTransferByte (0xff);
314 while (spiTransferByte (0xff) != 0xff)
331 int mscblockRead (U32 dwAddress, U8 * pbBuf)
335 U16 fb_timeout = 0xffff;
338 place = 512 * dwAddress;
339 mscblockCommand (CMD_READSINGLEBLOCK, place);
341 cardresp = mscblockResp8b ();
344 // Wait for startblock
348 firstblock = mscblockResp8b();
350 while (firstblock == 0xff && fb_timeout--);
352 if (cardresp != 0x00 || firstblock != 0xfe)
354 mscblockResp8bError (firstblock);
358 mscspiReceiveBlock (pbBuf, 512);
361 // Checksum (2 byte) - ignore for now
363 mscspiTransferByte (0xff);
364 mscspiTransferByte (0xff);