Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Има ли разлика между SD и MMC?
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=3217
Страница 1 от 2

Автор:  Реконструктор [ Нед Ное 05, 2006 4:52 pm ]
Заглавие:  Има ли разлика между SD и MMC?

Днес се пробвах да подкарам една SD карта на платката на Олимекс. Функциите на API-то в примера, предоставен от Олимекс за интерфейс към картата, почват с префикс mmc, което навежда на мисълта, че са дизайнати специално за mmc.
Тъй като още ме е страх да пиша, за сега само чета. :roll: При опит да прочета сектор 0 (партишън сектора), се получава странен резултат: последните 2 байта на сектора коректно са 0x55 и 0xAA, но по средата са само нули, като от време на време прескача по някой заблуден байт. Какво може да е - проблем със съвместимостта на стандартите, проблем с тайминга (в коментара в кода на Олимекс е посочена скорост на SPI ~1MHz), или нещо друго?

Автор:  Cekins [ Нед Ное 05, 2006 5:12 pm ]
Заглавие: 

Ми разликата има - MMC става да се чете от такова дето чете SD ама обратното май не става.

Автор:  Nikola Kirov [ Нед Ное 05, 2006 6:37 pm ]
Заглавие: 

По SPI интерфеис са съвместими.
Разгледай какво имаш по картата с WinHex,предполагам че имаш card reader към компа.

В началото на картата имаш MBR а не FAT.

Автор:  BrainStorm [ Нед Ное 05, 2006 10:27 pm ]
Заглавие: 

SD имат допълнителен набор от команди .. иначе основните са еднакви .. пъхаи смело нищо и няма ;)

Автор:  Реконструктор [ Пон Ное 06, 2006 10:41 am ]
Заглавие: 

BrainStorm написа:
SD имат допълнителен набор от команди .. иначе основните са еднакви .. пъхаи смело нищо и няма ;)


Там е работата, че нищо не става. :(

Автор:  FiTTiLA [ Пон Ное 06, 2006 12:30 pm ]
Заглавие: 

Реконструктор написа:
BrainStorm написа:
SD имат допълнителен набор от команди .. иначе основните са еднакви .. пъхаи смело нищо и няма ;)


Там е работата, че нищо не става. :(


Има разлика в инициализацията след ресет,
При SD:
CMD0
ACMD41
CMD2
CMD3

При MMC:
CMD0
CMD1
CMD2
CMD3

Пробвано е. Ако не се инициализира както трябва не чува петела :) .

Автор:  Реконструктор [ Вто Ное 07, 2006 11:21 am ]
Заглавие: 

fittila написа:
Има разлика в инициализацията след ресет,
При SD:
CMD0
ACMD41
CMD2
CMD3

При MMC:
CMD0
CMD1
CMD2
CMD3

Пробвано е. Ако не се инициализира както трябва не чува петела :) .


Тук намерих описана друга процедура за инициализация:

Цитат:
SD Card Identification Procedure
The SD card identification procedure is:
1. Use the MMC command register (MMCCMD) to issue the GO_IDLE_STATE (CMD0) command to the
MMC cards. Using MMCMD to issue the CMD0 command puts all cards (MMC and SD) in the idle
state and no response from the cards is expected.
2. Use MMCCMD to issue the APP_CMD (CMD55) command (R1 response is expected) to indicate that
the command that follows is an application command.
3. Use MMCCMD to send the SD_SEND_OP_COND (ACMD41) command with the voltage range
supported (R3 response is expected) to SD cards. Using MMCCMD to send the ACMD41 command
allows the host to identify and reject cards that do not match the VDD range that the host supports.
4. Use MMCCMD to send the ALL_SEND_CID (CMD2) command (R2 response is expected) to the MMC
cards. Using MMCCMD to send the CMD2 command notifies all cards to send their unique card
identification (CID) number. There should only be one card that successfully sends its full CID number
to the host. The successful card goes into identification state and does not respond to this command
again.
5. Use MMCMD to issue the SEND_RELATIVE_ADDR (CMD3) command (R1 response is expected) in
order to ask the card to publish a new relative address for future use to address the card in data
transfer mode.


Т.е. CMD0 -> CMD55 -> ACMD41, нататък не е важно май. Проблема с ACMD41 е, че трябва да се праща и някакъв "voltage range
supported", което май трябва да е захранването на картата?

Автор:  FiTTiLA [ Сря Ное 08, 2006 1:54 am ]
Заглавие: 

Рек, извинявай че не прочетох първия пост внимателно:(, така пише че трябва да е http://home.teleport.com/~brainy/fat32.htm, така че мисля че всичко ти е коректно инициализирано, и би трябвало до продължаваш напред, проблема не ти е clock-сигнала, по спецификация трябва да работи до 25MHz. Аз съм го търкалял при един. Форматирай SD на някое PC, запиши нещо от PC или някой фотоапарат, та да видиш тогава какво ще излезне по интерфейса.

Автор:  Реконструктор [ Сря Ное 08, 2006 10:43 am ]
Заглавие: 

Картата си е форматирана и записана. Просто не мога да прочета нищо от нея. :) Удари едно рамо с малко код де, не се стискай. :)

Автор:  FiTTiLA [ Чет Ное 09, 2006 11:10 am ]
Заглавие: 

Рек, зора е че нямам време, ама никакво, ако можеш да почакаш до събота, т.е. ако не си решил проблема да събота, тогава ще ми остане време да намеря нещата който съм правил, без туй ми предстой някакъв проект на темата. Айде до скоро :).

Автор:  Реконструктор [ Чет Ное 09, 2006 11:41 am ]
Заглавие: 

fittila написа:
Рек, зора е че нямам време, ама никакво, ако можеш да почакаш до събота, т.е. ако не си решил проблема да събота, тогава ще ми остане време да намеря нещата който съм правил, без туй ми предстой някакъв проект на темата. Айде до скоро :).


Не бързам за никъде. :) Вчера пробвах поредния код, който не проработи. :)

Автор:  FiTTiLA [ Пон Ное 13, 2006 12:53 pm ]
Заглавие: 

Ето част от кода (мисля че ще се оправиш :):
Код:
#define CS      0x04
#define CARD_DETECT   0x08
#define BUFFER_SIZE   0x200

typedef enum { true, false} bool;

xdata BYTE BufferINOUT[BUFFER_SIZE];

//***************************************************************************//
//                 SECURE DIGITAL COMMAND STRUCTURE DEFINE                   //
//***************************************************************************//
#define EMPTY      0
#define YES       1
#define NO      0
#define CMD      0
#define RD      1
#define WR      2
#define R1      0
#define R1b      1
#define R2      2
#define R3      3

// byte-addressable LONG
typedef union LONG {
   long l;
   unsigned char b[4];
} LONG;

// byte-addressable INT
typedef union INT {
   int i;
   unsigned char b[2];
} INT;

// byte-addressable unsigned long
typedef union ULONG {
   unsigned long l;
   unsigned char b[4];
} ULONG;

// byte-addressable unsigned int
typedef union UINT{
   unsigned int i;
   unsigned char b[2];
} UINT;

// This structure defines entries into the command table;
typedef struct {
   unsigned char command_byte;   // OpCode;
   unsigned char arg_required;   // Indicates argument requirement;
   unsigned char CRC;      // Holds CRC for command if necessary;
   unsigned char trans_type;   // Indicates command transfer type;
   unsigned char response;      // Indicates expected response;
   unsigned char var_length;   // Indicates varialble length transfer;
} COMMAND;

// Command table for SD. This table contains all commands available in SPI
// mode; Format of command entries is described above in command structure
// definition;
COMMAND code commandlist[29] = {
   { 0,NO ,0x95,CMD,R1 ,NO }, // CMD0; GO_IDLE_STATE: reset card;
   { 1,NO ,0xFF,CMD,R1 ,NO }, // CMD1; SEND_OP_COND: initialize SD card;
   { 9,NO ,0xFF,RD ,R1 ,NO }, // CMD9; SEND_CSD: get card specific data;
   {10,NO ,0xFF,RD ,R1 ,NO }, // CMD10; SEND_CID: get card identifier;
   {12,NO ,0xFF,CMD,R1 ,NO }, // CMD12; STOP_TRANSMISSION: end read;
   {13,NO ,0xFF,RD ,R1 ,NO }, // CMD13; SEND_STATUS: read card status;
   {16,YES,0xFF,CMD,R1 ,NO }, // CMD16; SET_BLOCKLEN: set block size;
   {17,YES,0xFF,RD ,R1 ,NO }, // CMD17; READ_SINGLE_BLOCK: read 1 block;
   {18,YES,0xFF,RD ,R1 ,YES}, // CMD18; READ_MULTIPLE_BLOCK: read > 1;
   {24,YES,0xFF,WR ,R1 ,NO }, // CMD24; WRITE_BLOCK: write 1 block;
   {25,YES,0xFF,WR ,R1 ,YES}, // CMD25; WRITE_MULTIPLE_BLOCK: write > 1;
   {27,NO ,0xFF,CMD,R1 ,NO }, // CMD27; PROGRAM_CSD: program CSD;
   {28,YES,0xFF,CMD,R1b,NO }, // CMD28; SET_WRITE_PROT: set wp for group;
   {29,YES,0xFF,CMD,R1b,NO }, // CMD29; CLR_WRITE_PROT: clear group wp;
   {30,YES,0xFF,CMD,R1 ,NO }, // CMD30; SEND_WRITE_PROT: check wp status;
   {32,YES,0xFF,CMD,R1 ,NO }, // CMD32; TAG_SECTOR_START: tag 1st erase;
   {33,YES,0xFF,CMD,R1 ,NO }, // CMD33; TAG_SECTOR_END: tag end(single);
   {34,YES,0xFF,CMD,R1 ,NO }, // CMD34; UNTAG_SECTOR: deselect for erase;
   {35,YES,0xFF,CMD,R1 ,NO }, // CMD35; TAG_ERASE_GROUP_START;
   {36,YES,0xFF,CMD,R1 ,NO }, // CMD36; TAG_ERASE_GROUP_END;
   {37,YES,0xFF,CMD,R1 ,NO }, // CMD37; UNTAG_ERASE_GROUP;
   {38,YES,0xFF,CMD,R1b,NO }, // CMD38; ERASE: erase all tagged sectors;
   {42,YES,0xFF,CMD,R1b,NO }, // CMD42; LOCK_UNLOCK;
   {58,NO ,0xFF,CMD,R3 ,NO }, // CMD58; READ_OCR: read OCR register in SPI mode;
   {59,YES,0xFF,CMD,R1 ,NO }, // CMD59; CRC_ON_OFF: toggles CRC checking;
   {41,NO ,0xFF,CMD,R1 ,NO }, // CMD41; SD_APP_OP_COND: initialize SD card;
   { 2,NO ,0xFF,RD ,R1 ,NO }, // CMD2; GET_CID
   { 3,NO ,0xFF,RD ,R1 ,NO }, // CMD3; GET_RCA
   {55,NO ,0xFF,CMD,R1 ,NO } //CMD55; APP_CMD
};

#define GO_IDLE_STATE      0
#define SEND_OP_COND      1
#define SEND_CSD      2
#define SEND_CID      3
#define STOP_TRANSMISSION   4
#define SEND_STATUS      5
#define SET_BLOCKLEN      6
#define READ_SINGLE_BLOCK   7
#define READ_MULTIPLE_BLOCK   8
#define WRITE_BLOCK      9
#define WRITE_MULTIPLE_BLOCK   10
#define PROGRAM_CSD      11
#define SET_WRITE_PROT      12
#define CLR_WRITE_PROT      13
#define SEND_WRITE_PROT      14
#define TAG_SECTOR_START   15
#define TAG_SECTOR_END      16
#define UNTAG_SECTOR      17
#define TAG_ERASE_GROUP_START   18
#define TAG_ERASE_GROUP_END   19
#define UNTAG_ERASE_GROUP   20
#define ERASE         21
#define LOCK_UNLOCK      22
#define READ_OCR      23
#define CRC_ON_OFF      24
#define SD_APP_OP_COND      25
#define GET_CID         26
#define GET_RCA         27
#define APP_CMD         28

// Start and stop data tokens for single and multiple
// block SD data operations
#define START_SBR 0xFE
#define START_MBR 0xFE
#define START_SBW 0xFE
#define START_MBW 0xFC
#define STOP_MBW 0xFD
// Mask for data response token after an SD write
#define DATA_RESP_MASK 0x11
// Mask for busy token in R1b response
#define BUSY_BIT 0x80

//***************************************************************************//
// SD_Command_Exec                                                          //
//***************************************************************************//
//
// This function generates the necessary SPI traffic for all SD SPI commands.
// The three parameters are described below:
//
// cmd: This parameter is used to index into the command table and read
// the desired command. The Command Table Index Constants allow the
// caller to use a meaningful constant name in the cmd parameter
// instead of a simple index number. For example, instead of calling
// SD_Command_Exec (0, argument, pchar) to send the SD into idle
// state, the user can call
// SD_Command_Exec (GO_IDLE_STATE, argument, pchar);
//
// argument: This parameter is used for SD commands that require an argument.
// SD arguments are 32-bits long and can be values such as an
// an address, a block length setting, or register settings for the
// SD.
//
// pchar: This parameter is a pointer to the local data location for SD
// data operations. When a read or write occurs, data will be stored
// or retrieved from the location pointed to by pchar.
//
// The SD_Command_Exec function indexes the command table using the cmd
// parameter. It reads the command table entry into memory and uses information
// from that entry to determine how to proceed. Returns the 16-bit card
// response value;
//
unsigned int SD_Command_Exec (unsigned char cmd, unsigned long argument, unsigned char *pchar){
   
   idata COMMAND current_command;         // Local space for the command table entry;
   idata ULONG long_arg;            // Union variable for easy byte transfers of the argument;   
   static unsigned long current_blklen = 512;   // Static variable that holds the current data block length;
   unsigned long old_blklen = 512;         // Temp variable to preserve data block length during temporary changes;
   idata unsigned int counter = 0;         // Byte counter for multi-byte fields;
   idata UINT card_response;         // Variable for storing card response;
   idata unsigned char data_resp;         // Variable for storing data response;
   idata unsigned char dummy_CRC;         // Dummy variable for storing CRC field;
   unsigned char dummy;
   current_command = commandlist[cmd];      // Retrieve desired command table entry from code space;
   SendCharUART0( 0xFF);         // Send buffer SPI clocks to ensure no
                  // SD operations are pending;

   OUTC &= ~CS;            // Select SD by pulling CS low;
   SendCharUART0( 0xFF);         // Send another byte of SPI clocks;

   // Issue command opcode;
   SendCharUART0( current_command.command_byte | 0x40);
   long_arg.l = argument;         // Make argument byte addressable;
   // If current command changes block
   // length, update block length variable
   // to keep track;
   // Command byte = 16 means that a set
   // block length command is taking place
   // and block length variable must be
   // set;
   if(current_command.command_byte == 16){
      current_blklen = argument;
   }
   // Command byte = 9 or 10 means that a
   // 16-byte register value is being read
   // from the card, block length must be
   // set to 16 bytes, and restored at the
   // end of the transfer;
   switch( current_command.command_byte){
      case 9:
      case 10:
         old_blklen = current_blklen;   // Command is a SEND_CSD or SEND_CID,
         current_blklen = 16;      // set block length to 16-bytes;
         break;
      case 13:
         old_blklen = current_blklen;   // Command is a SEND_STATUS,
         current_blklen = 4;      // set block length to 4-bytes;
         break;
      default:
         break;
   }
   // If an argument is required, transmit
   // one, otherwise transmit 4 bytes of
   // 0x00;
   if(current_command.arg_required == YES){
      counter = 0;
      while(counter <= 3){
         SendCharUART0( long_arg.b[counter]);
         counter++;
      }
   }else{
      counter = 0;
      while(counter <= 3){
         SendCharUART0( 0x00);
         counter++;
      }
   }
   SendCharUART0( current_command.CRC);         // Transmit CRC byte; In all cases except CMD0, this will be a dummy character;
   // The command table entry will indicate
   // what type of response to expect for
   // a given command; The following
   // conditional handles the SD response;
   switch( current_command.response){
      case R1:   // Read the R1 response from the card;
         do{
            card_response.b[0] = ReceiveCharUART0();   // Save the response;
         }while((card_response.b[0] & BUSY_BIT));
         break;
      case R1b:   // Read the R1b response;
         do{
            card_response.b[0] = ReceiveCharUART0();   // Save the response;
         }while((card_response.b[0] & BUSY_BIT));
         while( ReceiveCharUART0() == 0x00);         // When byte from card is non-zero,
         break;
      case R2:   // card is no longer busy, read R2 response
         do{
            card_response.b[0] = ReceiveCharUART0();   // Read first byte of response;
         }while((card_response.b[0] & BUSY_BIT));
         card_response.b[1] = ReceiveCharUART0();      // Read second byte of response;
         break;
      default:   // Read R3 response;
         do{
            card_response.b[0] = ReceiveCharUART0();   // Read first byte of response;
         }while((card_response.b[0] & BUSY_BIT));
         counter = 0;
         while(counter <= 3){               // Read next three bytes and store them
                              // in local memory; These bytes make up
            counter++;               // the Operating Conditions Register
            *pchar++ = ReceiveCharUART0();         // (OCR);
         }
   }

   switch(current_command.trans_type){      // This conditional handles all data
                     // operations; The command entry
                     // determines what type, if any, data
                     // operations need to occur;
      case RD:// Read data from the SD;
         // Wait for a start read token from
         // the SD;
         do{
            dummy = ReceiveCharUART0();
            if( dummy == START_SBR) break;
            if( !(dummy & 0xF0)) return dummy;
         }while( 1);      // Check for a start read token;

         counter = 0;            // Reset byte counter;
         // Read <current_blklen> bytes;
         while(counter < (unsigned int)current_blklen){
            *pchar++ = ReceiveCharUART0();   // Store data byte in local memory;
            counter++;         // Increment data byte counter;
         }
         // After all data is read, read the two
         // CRC bytes; These bytes are not used
         // in this mode, but the placeholders
         dummy_CRC = ReceiveCharUART0();      // must be read anyway;
         dummy_CRC = ReceiveCharUART0();
         break;

      case WR:// Write data to the SD;
         // Start by sending 8 SPI clocks so
         // the SD can prepare for the write;
         SendCharUART0( 0xFF);
         SendCharUART0( START_SBW);      // Send the start write block token;
         counter = 0;            // Reset byte counter;
         // Write <current_blklen> bytes to SD;
         while(counter < (unsigned int)current_blklen){
            SendCharUART0( *pchar++);   // Write data byte out through SPI;
            counter++;         // Increment byte counter;
         }
         SendCharUART0( 0xFF);         // Write CRC bytes (don’t cares);
         SendCharUART0( 0xFF);
         do{               // Read Data Response from card;
            data_resp = ReceiveCharUART0();
         }   // When bit 0 of the SD response
            // is clear, a valid data response
            // has been received;
         while((data_resp & DATA_RESP_MASK) != 0x01);
         // Wait for end of busy signal;
         while(ReceiveCharUART0() == 0x00);   // When a non-zero token is returned,
         // card is no longer busy;
         // Issue 8 SPI clocks so that all card
         SendCharUART0( 0xFF);
         break;

      default: break;
   }
   SendCharUART0( 0xFF);
   OUTC |= CS;      // Deselect memory card;
   // Send 8 more SPI clocks to ensure
   // the card has finished all necessary
   // operations;
   SendCharUART0( 0xFF);
   // Restore old block length if needed;
   if((current_command.command_byte == 9)||(current_command.command_byte == 10)){
      current_blklen = old_blklen;
   }
   return card_response.i;
}

//***************************************************************************//
//                           SD_FLASH_Init                                  //
//***************************************************************************//
//
// This function initializes the flash card, configures it to operate in SPI
// mode, and reads the operating conditions register to ensure that the device
// has initialized correctly. It also determines the size of the card by
// reading the Card Specific Data Register (CSD).
void SD_FLASH_Init (void)
{
   idata UINT card_status;            // Stores card status returned from SD function calls(SD_Command_Exec);
   idata unsigned char counter = 0;      // SPI byte counter;
   //idata unsigned int size;         // Stores size variable from card;
   BYTE *pchar;
   // register values;
   // temporary register values from SD;
   pchar = BufferINOUT;
   
   // STATE 1 OF INIT
   // Transmit at least 64 SPI clocks
   // before any bus comm occurs.
   for(counter = 0; counter < 10; counter++){
      SendCharUART0( 0xFF);
   }

   // STATE 2 OF INIT
   // Send the GO_IDLE_STATE command with
   // CS driven low; This causes the SD
   // to enter SPI mode;
   SD_Command_Exec( GO_IDLE_STATE,EMPTY,EMPTY);
   SD_Command_Exec( GO_IDLE_STATE,EMPTY,EMPTY);
   SD_Command_Exec( GO_IDLE_STATE,EMPTY,EMPTY);
   SD_Command_Exec( GO_IDLE_STATE,EMPTY,EMPTY);

   // STATE 4 OF INIT
   do{    // until the SD indicates that it is
      // no longer busy (ready for commands);
      card_status.i = SD_Command_Exec( SEND_OP_COND,EMPTY,EMPTY);
   }while ((card_status.b[0] & 0x01));

   // STATE 5 OF INIT
   // Operation Conditions (VDU Voltage Profile and Busy Status Information)
   // Register (OCR);
   SD_Command_Exec( READ_OCR, EMPTY,pchar);
   pchar += 4;

   // STATE 6 OF INIT
   // Card Identification information
   // Register (CID);
   SD_Command_Exec( SEND_CID, EMPTY, pchar);
   pchar += 16;

   // STATE 7 OF INIT
   // Card specific information
   // Register (CSD);
   SD_Command_Exec( SEND_CSD, EMPTY, pchar);
}

Автор:  FiTTiLA [ Пон Ное 13, 2006 12:56 pm ]
Заглавие: 

Ето и малко, и за crc-то:
Код:
// Computation of CRC-7 0x48 polynom (x^7 + x^3 + 1), Used in SD commands and responses.
unsigned char
crc7 (char *data, unsigned char length){
   unsigned char i, ibit, c, crc;
   crc = 0x00;                  // Set initial value

   for (i = 0; i < length; i++, data++){
      c = *data;
      for (ibit = 0; ibit < 8; ibit++){
         crc = crc << 1;
         if ((c ^ crc) & 0x80) crc = crc ^ 0x09;   // ^ is XOR
         c = c << 1;
      }
      crc = crc & 0x7F;
   }
   crc = crc << 1;      // SD card stores the result in the top 7 bits so shift them left 1
   crc |= 0x01;      // Should shift in a 1 not a 0
   return crc;
}

Автор:  FiTTiLA [ Вто Ное 14, 2006 11:14 am ]
Заглавие: 

Рек, какво стана? или съм се пънал за тоя дето клати гората :( .

Автор:  Реконструктор [ Вто Ное 14, 2006 11:23 am ]
Заглавие: 

Нямам време да го пробвам. :( Тия дни ще се пробвам да го подкарам.

Страница 1 от 2 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/