 | Код: #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); } |  |