Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
248 Kevin 1
// ***********************************************************
2
// File: mmc.c 
3
// Description: Library to access a MultiMediaCard 
4
//              functions: init, read, write ...
5
//  C. Speck / S. Schauer
6
//  Texas Instruments, Inc
7
//  June 2005
8
//
9
// Version 1.1
10
//   corrected comments about connection the MMC to the MSP430
11
//   increased timeout in mmcGetXXResponse
12
//
13
// ***********************************************************
14
// MMC Lib
15
// ***********************************************************
16
 
17
 
18
/* ***********************************************************
19
* THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
20
* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, 
21
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
22
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR 
23
* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE. 
24
* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET 
25
* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY 
26
* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR 
27
* YOUR USE OF THE PROGRAM.
28
*
29
* IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL, 
30
* CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY 
31
* THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED 
32
* OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT 
33
* OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM. 
34
* EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF 
35
* REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS 
36
* OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF 
37
* USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S 
38
* AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF 
39
* YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS 
40
* (U.S.$500).
41
*
42
* Unless otherwise stated, the Program written and copyrighted 
43
* by Texas Instruments is distributed as "freeware".  You may, 
44
* only under TI's copyright in the Program, use and modify the 
45
* Program without any charge or restriction.  You may 
46
* distribute to third parties, provided that you transfer a 
47
* copy of this license to the third party and the third party 
48
* agrees to these terms by its first use of the Program. You 
49
* must reproduce the copyright notice and any other legend of 
50
* ownership on each copy or partial copy, of the Program.
51
*
52
* You acknowledge and agree that the Program contains 
53
* copyrighted material, trade secrets and other TI proprietary 
54
* information and is protected by copyright laws, 
55
* international copyright treaties, and trade secret laws, as 
56
* well as other intellectual property laws.  To protect TI's 
57
* rights in the Program, you agree not to decompile, reverse 
58
* engineer, disassemble or otherwise translate any object code 
59
* versions of the Program to a human-readable form.  You agree 
60
* that in no event will you alter, remove or destroy any 
61
* copyright notice included in the Program.  TI reserves all 
62
* rights not specifically granted under this license. Except 
63
* as specifically provided herein, nothing in this agreement 
64
* shall be construed as conferring by implication, estoppel, 
65
* or otherwise, upon you, any license or other right under any 
66
* TI patents, copyrights or trade secrets.
67
*
68
* You may not use the Program in non-TI devices.
69
* ********************************************************* */
70
 
71
 
72
#ifndef _MMCLIB_C
73
#define _MMCLIB_C
74
//
75
//---------------------------------------------------------------
76
#include "mmc.h"
77
#include "hal_SPI.h"
78
#include "hal_hardware_board.h"
79
 
80
//#define withDMA
81
 
82
// Function Prototypes
83
char mmcGetResponse(void);
84
char mmcGetXXResponse(const char resp);
85
char mmcCheckBusy(void);
86
char mmcGoIdle();
87
 
88
// Initialize MMC card
89
char mmcInit(void)
90
{
91
    //raise CS and MOSI for 80 clock cycles
92
    //SendByte(0xff) 10 times with CS high
93
    //RAISE CS
94
    int i;
95
 
96
    // Port x Function           Dir       On/Off
97
    //         mmcCS         Out       0 - Active 1 - none Active
98
    //         Dout          Out       0 - off    1 - On -> init in SPI_Init
99
    //         Din           Inp       0 - off    1 - On -> init in SPI_Init
100
    //         Clk           Out       -                 -> init in SPI_Init
101
    //         mmcCD         In        0 - card inserted
102
 
103
//    // Init Port for MMC (default high)
104
//    MMC_PxOUT |= MMC_SIMO + MMC_SOMI + MMC_UCLK;
105
//    MMC_PxDIR |= MMC_SIMO + MMC_UCLK;
106
//    MMC_PxDIR &= ~MMC_SOMI;
107
//
108
//    // Chip Select
109
//    MMC_CS_PxOUT |= MMC_CS;
110
//    MMC_CS_PxDIR |= MMC_CS;
111
//
112
//	// Card Detect
113
//	MMC_CD_PxDIR &= ~MMC_CD;
114
 
115
    // Enable secondary function
116
#if SPI_SER_INTF == SER_INTF_BITBANG
117
    MMC_PxSEL |= MMC_SIMO + MMC_SOMI + MMC_UCLK;
118
#endif
119
 
120
    // Ping the card to check if it exists
121
 
122
    // Set the clock speed to something slow
123
    halSPISetSpeedLow();
124
 
125
    // Initialization sequence on powerup
126
    MMC_CS_HIGH();
127
    for(i=0;i<=9;i++)
128
        spiSendByte(DUMMY_CHAR);
129
 
130
    __delay_cycles(100);
131
 
132
    return (mmcGoIdle());
133
}
134
 
135
 
136
// Set MMC in Idle mode
137
char mmcGoIdle()
138
{
139
    char response=0x01;
140
    MMC_CS_LOW();
141
 
142
    // Send Command 0 to put MMC in SPI mode
143
    mmcSendCmd(MMC_GO_IDLE_STATE,0,0x95);
144
 
145
    // Now wait until idle state bit is cleared
146
    if(mmcGetResponse()!=0x01)
147
        return MMC_INIT_ERROR;
148
 
149
    while(response==0x01)
150
    {
151
        MMC_CS_HIGH();
152
        spiSendByte(DUMMY_CHAR);
153
        MMC_CS_LOW();
154
        mmcSendCmd(MMC_SEND_OP_COND,0x00,0xff);
155
        response=mmcGetResponse();
156
    }
157
 
158
    MMC_CS_HIGH();
159
 
160
    // Card is now initialized, increase the clock speed
161
    halSPISetSpeedHigh();
162
 
163
    spiSendByte(DUMMY_CHAR);
164
    spiSendByte(DUMMY_CHAR);
165
 
166
    return (MMC_SUCCESS);
167
}
168
 
169
// MMC Get Response
170
char mmcGetResponse(void)
171
{
172
    //Response comes 1-8bytes after command
173
    //the first bit will be a 0
174
    //followed by an error code
175
    //data will be 0xff until response
176
    int i=0;
177
 
178
    volatile unsigned char response;
179
 
180
    while(i<=64)
181
    {
182
        response=spiSendByte(DUMMY_CHAR);
183
        if(response==0x00)break;
184
        if(response==0x01)break;
185
        i++;
186
    }
187
    return response;
188
}
189
 
190
char mmcGetXXResponse(const char resp)
191
{
192
    //Response comes 1-8bytes after command
193
    //the first bit will be a 0
194
    //followed by an error code
195
    //data will be 0xff until response
196
    int i=0;
197
 
198
    char response;
199
 
200
    while(i<=1000)
201
    {
202
        response=spiSendByte(DUMMY_CHAR);
203
        if(response==resp)break;
204
        i++;
205
    }
206
    return response;
207
}
208
 
209
// Check if MMC card is still busy
210
char mmcCheckBusy(void)
211
{
212
    //Response comes 1-8bytes after command
213
    //the first bit will be a 0
214
    //followed by an error code
215
    //data will be 0xff until response
216
    int i=0;
217
 
218
    char response;
219
    char rvalue;
220
    while(i<=64)
221
    {
222
        response=spiSendByte(DUMMY_CHAR);
223
        response &= 0x1f;
224
        switch(response)
225
        {
226
            case 0x05: rvalue=MMC_SUCCESS;break;
227
            case 0x0b: return(MMC_CRC_ERROR);
228
            case 0x0d: return(MMC_WRITE_ERROR);
229
            default:
230
                rvalue = MMC_OTHER_ERROR;
231
            break;
232
        }
233
        if(rvalue==MMC_SUCCESS)break;
234
        i++;
235
    }
236
    i=0;
237
    do
238
    {
239
        response=spiSendByte(DUMMY_CHAR);
240
        i++;
241
    }while(response==0);
242
    return response;
243
}
244
// The card will respond with a standard response token followed by a data
245
// block suffixed with a 16 bit CRC.
246
 
247
// read a size Byte big block beginning at the address.
248
char mmcReadBlock(const unsigned long address, const unsigned long count, unsigned char *pBuffer)
249
{
250
    char rvalue = MMC_RESPONSE_ERROR;
251
 
252
    // Set the block length to read
253
    if (mmcSetBlockLength (count) == MMC_SUCCESS)   // block length could be set
254
    {
255
        // CS = LOW (on)
256
        MMC_CS_LOW ();
257
        // send read command MMC_READ_SINGLE_BLOCK=CMD17
258
        mmcSendCmd (MMC_READ_SINGLE_BLOCK,address, 0xFF);
259
        // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command
260
        // it will do this by sending an affirmative response
261
        // in the R1 format (0x00 is no errors)
262
        if (mmcGetResponse() == 0x00)
263
        {
264
            // now look for the data token to signify the start of
265
            // the data
266
            if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN)
267
            {
268
                // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block
269
                spiReadFrame(pBuffer, count);
270
                // get CRC bytes (not really needed by us, but required by MMC)
271
                spiSendByte(DUMMY_CHAR);
272
                spiSendByte(DUMMY_CHAR);
273
                rvalue = MMC_SUCCESS;
274
            }
275
            else
276
            {
277
                // the data token was never received
278
                rvalue = MMC_DATA_TOKEN_ERROR;      // 3
279
            }
280
        }
281
        else
282
        {
283
            // the MMC never acknowledge the read command
284
            rvalue = MMC_RESPONSE_ERROR;          // 2
285
        }
286
    }
287
    else
288
    {
289
        rvalue = MMC_BLOCK_SET_ERROR;           // 1
290
    }
291
    MMC_CS_HIGH ();
292
    spiSendByte(DUMMY_CHAR);
293
    return rvalue;
294
}
295
 
296
char mmcWriteBlock (const unsigned long address, const unsigned long count, unsigned char *pBuffer)
297
{
298
    char rvalue = MMC_RESPONSE_ERROR;         // MMC_SUCCESS;
299
    //  char c = 0x00;
300
 
301
    // Set the block length to read
302
    if (mmcSetBlockLength (count) == MMC_SUCCESS)   // block length could be set
303
    {
304
        // CS = LOW (on)
305
        MMC_CS_LOW ();
306
        // send write command
307
        mmcSendCmd (MMC_WRITE_BLOCK,address, 0xFF);
308
 
309
        // check if the MMC acknowledged the write block command
310
        // it will do this by sending an affirmative response
311
        // in the R1 format (0x00 is no errors)
312
        if (mmcGetXXResponse(MMC_R1_RESPONSE) == MMC_R1_RESPONSE)
313
        {
314
            spiSendByte(DUMMY_CHAR);
315
            // send the data token to signify the start of the data
316
            spiSendByte(0xfe);
317
            // clock the actual data transfer and transmitt the bytes
318
 
319
            spiSendFrame(pBuffer, count);
320
 
321
            // put CRC bytes (not really needed by us, but required by MMC)
322
            spiSendByte(DUMMY_CHAR);
323
            spiSendByte(DUMMY_CHAR);
324
            // read the data response xxx0<status>1 : status 010: Data accected, status 101: Data
325
            //   rejected due to a crc error, status 110: Data rejected due to a Write error.
326
            mmcCheckBusy();
327
            rvalue = MMC_SUCCESS;
328
        }
329
        else
330
        {
331
            // the MMC never acknowledge the write command
332
            rvalue = MMC_RESPONSE_ERROR;   // 2
333
        }
334
    }
335
    else
336
    {
337
        rvalue = MMC_BLOCK_SET_ERROR;   // 1
338
    }
339
    // give the MMC the required clocks to finish up what ever it needs to do
340
    //  for (i = 0; i < 9; ++i)
341
    //    spiSendByte(0xff);
342
 
343
    MMC_CS_HIGH ();
344
    // Send 8 Clock pulses of delay.
345
    spiSendByte(DUMMY_CHAR);
346
    return rvalue;
347
}
348
 
349
 
350
// Send command to MMC
351
void mmcSendCmd (const char cmd, unsigned long data, const char crc)
352
{
353
    unsigned char frame[6];
354
    char temp;
355
    int i;
356
    frame[0]=(cmd|0x40);
357
    for(i=3;i>=0;i--){
358
        temp=(char)(data>>(8*i));
359
        frame[4-i]=(temp);
360
    }
361
    frame[5]=(crc);
362
    spiSendFrame(frame,6);
363
}
364
 
365
 
366
//--------------- set blocklength 2^n ------------------------------------------------------
367
char mmcSetBlockLength (const unsigned long blocklength)
368
{
369
    // CS = LOW (on)
370
    MMC_CS_LOW ();
371
    // Set the block length to read
372
    mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF);
373
 
374
    // get response from MMC - make sure that its 0x00 (R1 ok response format)
375
    if(mmcGetResponse()!=0x00)
376
    { mmcInit();
377
        mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF);
378
        mmcGetResponse();
379
    }
380
 
381
    MMC_CS_HIGH ();
382
 
383
    // Send 8 Clock pulses of delay.
384
    spiSendByte(DUMMY_CHAR);
385
 
386
    return MMC_SUCCESS;
387
}
388
 
389
 
390
// Reading the contents of the CSD and CID registers in SPI mode is a simple read-block transaction.
391
char mmcReadRegister (const char cmd_register, const unsigned char length, unsigned char *pBuffer)
392
{
393
    char uc = 0;
394
    char rvalue = MMC_TIMEOUT_ERROR;
395
 
396
    if (mmcSetBlockLength (length) == MMC_SUCCESS)
397
    {
398
        MMC_CS_LOW ();
399
        // CRC not used: 0xff as last byte
400
        mmcSendCmd(cmd_register, 0x000000, 0xff);
401
 
402
        // wait for response
403
        // in the R1 format (0x00 is no errors)
404
        if (mmcGetResponse() == 0x00)
405
        {
406
            if (mmcGetXXResponse(0xfe)== 0xfe)
407
                for (uc = 0; uc < length; uc++)
408
                    pBuffer[uc] = spiSendByte(DUMMY_CHAR);  //mmc_buffer[uc] = spiSendByte(0xff);
409
            // get CRC bytes (not really needed by us, but required by MMC)
410
            spiSendByte(DUMMY_CHAR);
411
            spiSendByte(DUMMY_CHAR);
412
            rvalue = MMC_SUCCESS;
413
        }
414
        else
415
            rvalue = MMC_RESPONSE_ERROR;
416
        // CS = HIGH (off)
417
        MMC_CS_HIGH ();
418
 
419
        // Send 8 Clock pulses of delay.
420
        spiSendByte(DUMMY_CHAR);
421
    }
422
    MMC_CS_HIGH ();
423
    return rvalue;
424
} 
425
 
426
 
427
#include "math.h"
428
unsigned long mmcReadCardSize(void)
429
{
430
    // Read contents of Card Specific Data (CSD)
431
 
432
    unsigned long MMC_CardSize;
433
    unsigned short i,        // index
434
                    j,      // index
435
                    b,      // temporary variable
436
                    response,   // MMC response to command
437
                    mmc_C_SIZE;
438
 
439
    unsigned char mmc_READ_BL_LEN,  // Read block length
440
                    mmc_C_SIZE_MULT;
441
 
442
    MMC_CS_LOW ();
443
 
444
    spiSendByte(MMC_READ_CSD);   // CMD 9
445
    for(i=4; i>0; i--)      // Send four dummy bytes
446
        spiSendByte(0);
447
    spiSendByte(DUMMY_CHAR);   // Send CRC byte
448
 
449
    response = mmcGetResponse();
450
 
451
    // data transmission always starts with 0xFE
452
    b = spiSendByte(DUMMY_CHAR);
453
 
454
    if( !response )
455
    {
456
        while (b != 0xFE) b = spiSendByte(DUMMY_CHAR);
457
        // bits 127:87
458
        for(j=5; j>0; j--)          // Host must keep the clock running for at
459
            b = spiSendByte(DUMMY_CHAR);
460
 
461
        // 4 bits of READ_BL_LEN
462
        // bits 84:80
463
        b =spiSendByte(DUMMY_CHAR);  // lower 4 bits of CCC and
464
        mmc_READ_BL_LEN = b & 0x0F;
465
        b = spiSendByte(DUMMY_CHAR);
466
        // bits 73:62  C_Size
467
        // xxCC CCCC CCCC CC
468
        mmc_C_SIZE = (b & 0x03) << 10;
469
        b = spiSendByte(DUMMY_CHAR);
470
        mmc_C_SIZE += b << 2;
471
        b = spiSendByte(DUMMY_CHAR);
472
        mmc_C_SIZE += b >> 6;
473
        // bits 55:53
474
        b = spiSendByte(DUMMY_CHAR);
475
        // bits 49:47
476
        mmc_C_SIZE_MULT = (b & 0x03) << 1;
477
        b = spiSendByte(DUMMY_CHAR);
478
        mmc_C_SIZE_MULT += b >> 7;
479
        // bits 41:37
480
        b = spiSendByte(DUMMY_CHAR);
481
        b = spiSendByte(DUMMY_CHAR);
482
        b = spiSendByte(DUMMY_CHAR);
483
        b = spiSendByte(DUMMY_CHAR);
484
        b = spiSendByte(DUMMY_CHAR);
485
    }
486
 
487
    for(j=4; j>0; j--)          // Host must keep the clock running for at
488
        b = spiSendByte(DUMMY_CHAR);  // least Ncr (max = 4 bytes) cycles after
489
                                                             // the card response is received
490
    b = spiSendByte(DUMMY_CHAR);
491
    MMC_CS_LOW ();
492
 
493
    MMC_CardSize = (mmc_C_SIZE + 1);
494
    // power function with base 2 is better with a loop
495
    // i = (pow(2,mmc_C_SIZE_MULT+2)+0.5);
496
    for(i = 2,j=mmc_C_SIZE_MULT+2; j>1; j--)
497
        i <<= 1;
498
    MMC_CardSize *= i;
499
    // power function with base 2 is better with a loop
500
    //i = (pow(2,mmc_READ_BL_LEN)+0.5);
501
    for(i = 2,j=mmc_READ_BL_LEN; j>1; j--)
502
        i <<= 1;
503
    MMC_CardSize *= i;
504
 
505
    return (MMC_CardSize);
506
 
507
}
508
 
509
char mmcPing(void) {
510
	if (!(MMC_CD_PxIN & MMC_CD))
511
		return (MMC_SUCCESS);
512
	else
513
		return (MMC_INIT_ERROR);
514
}
515
 
516
#ifdef withDMA
517
#ifdef __IAR_SYSTEMS_ICC__
518
#pragma vector = DACDMA_VECTOR
519
__interrupt void DMA_isr(void)
520
#endif
521
 
522
#ifdef __TI_COMPILER_VERSION__
523
__interrupt void DMA_isr(void);
524
DMA_ISR(DMA_isr)
525
__interrupt void DMA_isr(void)
526
#endif
527
{
528
    DMA0CTL &= ~(DMAIFG);
529
    LPM3_EXIT;
530
}
531
#endif
532
 
533
 
534
//---------------------------------------------------------------------
535
#endif /* _MMCLIB_C */