Dependencies:   mbed

Revision:
3:68ef62208d4d
Parent:
2:849162a1207f
--- a/SDFileSystem.cpp	Mon Dec 14 22:32:28 2009 +0000
+++ b/SDFileSystem.cpp	Thu Dec 31 15:11:08 2009 +0000
@@ -1,7 +1,10 @@
 /* mbed Microcontroller Library - SDFileSystem
  * Copyright (c) 2008-2009, sford
- *
- * Introduction
+ */
+ 
+// VERY DRAFT CODE! Needs serious rework/refactoring 
+ 
+/* Introduction
  * ------------
  * SD and MMC cards support a number of interfaces, but common to them all
  * is one based on SPI. This is the one I'm implmenting because it means
@@ -112,11 +115,20 @@
 #define R1_ADDRESS_ERROR        (1 << 5)
 #define R1_PARAMETER_ERROR      (1 << 6)
 
-int SDFileSystem::disk_initialize() {
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
 
-    _spi.frequency(100000); // Set to 100kHz for initialisation
-    
-    // Initialise the card by clocking it with cs = 1
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
     _cs = 1;
     for(int i=0; i<16; i++) {   
         _spi.write(0xFF);
@@ -125,38 +137,58 @@
     // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
     if(_cmd(0, 0) != R1_IDLE_STATE) { 
         fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
-        return 1;
+        return SDCARD_FAIL;
     }
 
+    // send CMD8 to determine whther it is ver 2.x
     int r = _cmd8();
     if(r == R1_IDLE_STATE) {
-        printf("SD version 2.x\n");
+        return initialise_card_v2();
     } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
-        printf("SD version 1.x\n");
+        return initialise_card_v1();
     } else {
-        error("Unknown SD version\n");
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
     }
-        
-    // ACMD41 to give host capacity support (repeat until not busy)
-    // ACMD41 is application specific command, so we send APP_CMD (CMD55) beforehand
-    for(int i=0;; i++) {
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
         _cmd(55, 0); 
-        int response = _cmd(41, 0);
-        if(response == 0) { 
-            break;
-        } else if(i > SD_COMMAND_TIMEOUT) {
-            fprintf(stderr, "Timeout waiting for card\n");
-            return 1;
-        }    
+        if(_cmd(41, 0) == 0) { 
+            return SDCARD_V1;
+        }
     }
 
-    printf("OK\n");
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            _cmd58();
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+//    printf("init card = %d\n", i);
+//    printf("OK\n");
 
     _sectors = _sd_sectors();
 
     // Set block length to 512 (CMD16)
     if(_cmd(16, 512) != 0) {
-        fprintf(stderr, "Set block timeout\n");
+        fprintf(stderr, "Set 512-byte block timed out\n");
         return 1;
     }
         
@@ -216,6 +248,60 @@
     _spi.write(0xFF);
     return -1; // timeout
 }
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
 
 int SDFileSystem::_cmd8() {
     _cs = 0; 
@@ -310,7 +396,7 @@
 int SDFileSystem::_sd_sectors() {
 
     // CMD9, Response R2 (R1 byte + 16-byte block read)
-    if(_cmd(9, 0) != 0) {
+    if(_cmdx(9, 0) != 0) {
         fprintf(stderr, "Didn't get a response from the disk\n");
         return 0;
     }
@@ -324,25 +410,32 @@
     // csd_structure : csd[127:126]
     // c_size        : csd[73:62]
     // c_size_mult   : csd[49:47]
-    // read_bl_len   : csd[83:80] 
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
 
     int csd_structure = ext_bits(csd, 127, 126);
     int c_size = ext_bits(csd, 73, 62);
     int c_size_mult = ext_bits(csd, 49, 47);
     int read_bl_len = ext_bits(csd, 83, 80);
+
+//    printf("CSD_STRUCT = %d\n", csd_structure);
     
     if(csd_structure != 0) {
-        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures");
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
         return 0;
     }
+             
+    // memory capacity = BLOCKNR * BLOCK_LEN
+    // where
+    //  BLOCKNR = (C_SIZE+1) * MULT
+    //  MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+    //  BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)         
                             
-    int blocks = (c_size + 1) * (1 << (c_size_mult + 2));
-    int block_size = 1 << read_bl_len;
-
-    if(block_size != 512) {
-        fprintf(stderr, "This disk tastes funny! I only like 512-byte blocks");
-        return 0;
-    }
-    
+    int block_len = 1 << read_bl_len;
+    int mult = 1 << (c_size_mult + 2);
+    int blocknr = (c_size + 1) * mult;
+    int capacity = blocknr * block_len;
+        
+    int blocks = capacity / 512;
+        
     return blocks;
 }