Mmcsd.c
From Mech
Revision as of 17:57, 11 February 2009 by Mat Kotowsky (talk | contribs)
///////////////////////////////////////////////////////////////////////// //// MMCSD.c //// //// //// //// This is a low-level driver for MMC and SD cards. //// //// //// //// --User Functions-- //// //// //// //// mmcsd_init(): Initializes the media. //// //// //// //// mmcsd_read_byte(a, p) //// //// Reads a byte from the MMC/SD card at location a, saves to //// //// pointer p. Returns 0 if OK, non-zero if error. //// //// //// //// mmcsd_read_data(a, n, p) //// //// Reads n bytes of data from the MMC/SD card starting at address //// //// a, saves result to pointer p. Returns 0 if OK, non-zero if //// //// error. //// //// //// //// mmcsd_flush_buffer() //// //// The two user write functions (mmcsd_write_byte() and //// //// mmcsd_write_data()) maintain a buffer to speed up the writing //// //// process. Whenever a read or write is performed, the write //// //// buffer is loaded with the specified page and only the //// //// contents of this buffer is changed. If any future writes //// //// cross a page boundary then the buffer in RAM is written //// //// to the MMC/SD and then the next page is loaded into the //// //// buffer. mmcsd_flush_buffer() forces the contents in RAM //// //// to the MMC/SD card. Returns 0 if OK, non-zero if errror. //// //// //// //// mmcsd_write_byte(a, d) //// //// Writes data byte d to the MMC/SD address a. Intelligently //// //// manages a write buffer, therefore you may need to call //// //// mmcsd_flush_buffer() to flush the buffer. //// //// //// //// mmcsd_write_data(a, n, p) //// //// Writes n bytes of data from pointer p to the MMC/SD card //// //// starting at address a. This function intelligently manages //// //// a write buffer, therefore if you may need to call //// //// mmcsd_flush_buffer() to flush any buffered characters. //// //// returns 0 if OK, non-zero if error. //// //// //// //// mmcsd_read_block(a, s, p) //// //// Reads an entire page from the SD/MMC. Keep in mind that the //// //// start of the read has to be aligned to a block //// //// (Address % 512 = 0). Therefore s must be evenly divisible by //// //// 512. At the application level it is much more effecient to //// //// to use mmcsd_read_data() or mmcsd_read_byte(). Returns 0 //// //// if successful, non-zero if error. //// //// //// //// mmcsd_write_block(a, s, p): //// //// Writes an entire page to the SD/MMC. This will write an //// //// entire page to the SD/MMC, so the address and size must be //// //// evenly divisble by 512. At the application level it is much //// //// more effecient to use mmcsd_write_data() or mmcsd_write_byte().//// //// Returns 0 if successful, non-zero if error. //// //// //// //// mmcsd_print_cid(): Displays all data in the Card Identification //// //// Register. Note this only works on SD cards. //// //// //// //// mmcsd_print_csd(): Displays all data in the Card Specific Data //// //// Register. Note this only works on SD cards. //// //// //// //// //// //// --Non-User Functions-- //// //// //// //// mmcsd_go_idle_state(): Sends the GO_IDLE_STATE command to the //// //// SD/MMC. //// //// mmcsd_send_op_cond(): Sends the SEND_OP_COND command to the //// //// SD. Note this command only works on SD. //// //// mmcsd_send_if_cond(): Sends the SEND_IF_COND command to the //// //// SD. Note this command only works on SD. //// //// mmcsd_sd_status(): Sends the SD_STATUS command to the SD. Note //// //// This command only works on SD cards. //// //// mmcsd_send_status(): Sends the SEND_STATUS command to the //// //// SD/MMC. //// //// mmcsd_set_blocklen(): Sends the SET_BLOCKLEN command along with //// //// the desired block length. //// //// mmcsd_app_cmd(): Sends the APP_CMD command to the SD. This only //// //// works on SD cards and is used just before any //// //// SD-only command (e.g. send_op_cond()). //// //// mmcsd_read_ocr(): Sends the READ_OCR command to the SD/MMC. //// //// mmcsd_crc_on_off(): Sends the CRC_ON_OFF command to the SD/MMC //// //// along with a bit to turn the CRC on/off. //// //// mmcsd_send_cmd(): Sends a command and argument to the SD/MMC. //// //// mmcsd_get_r1(): Waits for an R1 response from the SD/MMC and //// //// then saves the response to a buffer. //// //// mmcsd_get_r2(): Waits for an R2 response from the SD/MMC and //// //// then saves the response to a buffer. //// //// mmcsd_get_r3(): Waits for an R3 response from the SD/MMC and //// //// then saves the response to a buffer. //// //// mmcsd_get_r7(): Waits for an R7 response from the SD/MMC and //// //// then saves the response to a buffer. //// //// mmcsd_wait_for_token(): Waits for a specified token from the //// //// SD/MMC. //// //// mmcsd_crc7(): Generates a CRC7 using a pointer to some data, //// //// and how many bytes long the data is. //// //// mmcsd_crc16(): Generates a CRC16 using a pointer to some data, //// //// and how many bytes long the data is. //// //// //// ///////////////////////////////////////////////////////////////////////// //// (C) Copyright 2007 Custom Computer Services //// //// This source code may only be used by licensed users of the CCS //// //// C compiler. This source code may only be distributed to other //// //// licensed users of the CCS C compiler. No other use, //// //// reproduction or distribution is permitted without written //// //// permission. Derivative programs created using this software //// //// in object code form are not restricted in any way. //// ///////////////////////////////////////////////////////////////////////// #ifndef MMCSD_C #define MMCSD_C ///////////////////// //// //// //// User Config //// //// //// ///////////////////// #ifndef MMCSD_PIN_SCL #define MMCSD_PIN_SCL PIN_C3 //o #define MMCSD_PIN_SDI PIN_C4 //i #define MMCSD_PIN_SDO PIN_C5 //o #define MMCSD_PIN_SELECT PIN_C2 //o #endif #use spi(MASTER, DI=MMCSD_PIN_SDI, DO=MMCSD_PIN_SDO, CLK=MMCSD_PIN_SCL, BITS=8, MSB_FIRST, IDLE=1, stream=mmcsd_spi) //////////////////////// //// //// //// Useful Defines //// //// //// //////////////////////// enum MMCSD_err {MMCSD_GOODEC = 0, MMCSD_IDLE = 0x01, MMCSD_ERASE_RESET = 0x02, MMCSD_ILLEGAL_CMD = 0x04, MMCSD_CRC_ERR = 0x08, MMCSD_ERASE_SEQ_ERR = 0x10, MMCSD_ADDR_ERR = 0x20, MMCSD_PARAM_ERR = 0x40, RESP_TIMEOUT = 0x80}; #define GO_IDLE_STATE 0 #define SEND_OP_COND 1 #define SEND_IF_COND 8 #define SEND_CSD 9 #define SEND_CID 10 #define SD_STATUS 13 #define SEND_STATUS 13 #define SET_BLOCKLEN 16 #define READ_SINGLE_BLOCK 17 #define WRITE_BLOCK 24 #define SD_SEND_OP_COND 41 #define APP_CMD 55 #define READ_OCR 58 #define CRC_ON_OFF 59 #define IDLE_TOKEN 0x01 #define DATA_START_TOKEN 0xFE #define MMCSD_MAX_BLOCK_SIZE 512 //////////////////////// /// /// /// Global Variables /// /// /// //////////////////////// int g_mmcsd_buffer[MMCSD_MAX_BLOCK_SIZE]; int1 g_CRC_enabled; int1 g_MMCSDBufferChanged; int32 g_mmcsdBufferAddress; enum _card_type{SD, MMC} g_card_type; ///////////////////////////// //// //// //// Function Prototypes //// //// //// ///////////////////////////// MMCSD_err mmcsd_init(); MMCSD_err mmcsd_read_data(int32 address, int16 size, int* ptr); MMCSD_err mmcsd_read_block(int32 address, int16 size, int* ptr); MMCSD_err mmcsd_write_data(int32 address, int16 size, int* ptr); MMCSD_err mmcsd_write_block(int32 address, int16 size, int* ptr); MMCSD_err mmcsd_go_idle_state(void); MMCSD_err mmcsd_send_op_cond(void); MMCSD_err mmcsd_send_if_cond(int r7[]); MMCSD_err mmcsd_print_csd(); MMCSD_err mmcsd_print_cid(); MMCSD_err mmcsd_sd_status(int r2[]); MMCSD_err mmcsd_send_status(int r2[]); MMCSD_err mmcsd_set_blocklen(int32 blocklen); MMCSD_err mmcsd_read_single_block(int32 address); MMCSD_err mmcsd_write_single_block(int32 address); MMCSD_err mmcsd_sd_send_op_cond(void); MMCSD_err mmcsd_app_cmd(void); MMCSD_err mmcsd_read_ocr(int* r1); MMCSD_err mmcsd_crc_on_off(int1 crc_enabled); MMCSD_err mmcsd_send_cmd(int cmd, int32 arg); MMCSD_err mmcsd_get_r1(void); MMCSD_err mmcsd_get_r2(int r2[]); MMCSD_err mmcsd_get_r3(int r3[]); MMCSD_err mmcsd_get_r7(int r7[]); MMCSD_err mmcsd_wait_for_token(int token); unsigned int8 mmcsd_crc7(char *data, unsigned int8 length); unsigned int16 mmcsd_crc16(char *data, unsigned int8 length); void mmcsd_select(); void mmcsd_deselect(); /// Fast Functions ! /// MMCSD_err mmcsd_load_buffer(void); MMCSD_err mmcsd_flush_buffer(void); MMCSD_err mmcsd_move_buffer(int32 new_addr); MMCSD_err mmcsd_read_byte(int32 addr, char* data); MMCSD_err mmcsd_write_byte(int32 addr, char data); ////////////////////////////////// //// //// //// Function Implementations //// //// //// ////////////////////////////////// MMCSD_err mmcsd_init() { int i, r1; g_CRC_enabled = TRUE; g_mmcsdBufferAddress = 0; output_drive(MMCSD_PIN_SCL); output_drive(MMCSD_PIN_SDO); output_drive(MMCSD_PIN_SELECT); output_float(MMCSD_PIN_SDI); mmcsd_deselect(); delay_ms(15); /* begin initialization */ i = 0; do { delay_ms(1); mmcsd_select(); r1=mmcsd_go_idle_state(); mmcsd_deselect(); i++; if(i == 0xFF) { mmcsd_deselect(); return r1; } } while(!bit_test(r1, 0)); i = 0; do { delay_ms(1); mmcsd_select(); r1=mmcsd_send_op_cond(); mmcsd_deselect(); i++; if(i == 0xFF) { mmcsd_deselect(); return r1; } } while(r1 & MMCSD_IDLE); /* figure out if we have an SD or MMC */ mmcsd_select(); r1=mmcsd_app_cmd(); r1=mmcsd_sd_send_op_cond(); mmcsd_deselect(); /* an mmc will return an 0x04 here */ if(r1 == 0x04) g_card_type = MMC; else g_card_type = SD; /* set block length to 512 bytes */ mmcsd_select(); r1 = mmcsd_set_blocklen(MMCSD_MAX_BLOCK_SIZE); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } mmcsd_deselect(); /* turn CRCs off to speed up reading/writing */ mmcsd_select(); r1 = mmcsd_crc_on_off(0); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } mmcsd_deselect(); r1 = mmcsd_load_buffer(); return r1; } MMCSD_err mmcsd_read_data(int32 address, int16 size, int* ptr) { MMCSD_err r1; int16 i; // counter for loops for(i = 0; i < size; i++) { r1 = mmcsd_read_byte(address++, ptr++); if(r1 != MMCSD_GOODEC) return r1; } return MMCSD_GOODEC; } MMCSD_err mmcsd_read_block(int32 address, int16 size, int* ptr) { MMCSD_err ec; int16 i; // counter for loops // send command mmcsd_select(); ec = mmcsd_read_single_block(address); if(ec != MMCSD_GOODEC) { mmcsd_deselect(); return ec; } // wait for the data start token ec = mmcsd_wait_for_token(DATA_START_TOKEN); if(ec != MMCSD_GOODEC) { mmcsd_deselect(); return ec; } // read in the data for(i = 0; i < size; i += 1) ptr[i] = spi_xfer(mmcsd_spi, 0xFF); if(g_CRC_enabled) { /* check the crc */ if(make16(spi_xfer(mmcsd_spi, 0xFF), spi_xfer(mmcsd_spi, 0xFF)) != mmcsd_crc16(g_mmcsd_buffer, MMCSD_MAX_BLOCK_SIZE)) { mmcsd_deselect(); return MMCSD_CRC_ERR; } } else { /* have the card transmit the CRC, but ignore it */ spi_xfer(mmcsd_spi, 0xFF); spi_xfer(mmcsd_spi, 0xFF); } mmcsd_deselect(); return MMCSD_GOODEC; } MMCSD_err mmcsd_write_data(int32 address, int16 size, int* ptr) { MMCSD_err ec; int16 i; // counter for loops for(i = 0; i < size; i++) { ec = mmcsd_write_byte(address++, *ptr++); if(ec != MMCSD_GOODEC) return ec; } return MMCSD_GOODEC; } MMCSD_err mmcsd_write_block(int32 address, int16 size, int* ptr) { MMCSD_err ec; int16 i; // send command mmcsd_select(); ec = mmcsd_write_single_block(address); if(ec != MMCSD_GOODEC) { mmcsd_deselect(); return ec; } // send a data start token spi_xfer(mmcsd_spi, DATA_START_TOKEN); // send all the data for(i = 0; i < size; i += 1) spi_xfer(mmcsd_spi, ptr[i]); // if the CRC is enabled we have to calculate it, otherwise just send an 0xFFFF if(g_CRC_enabled) spi_xfer(mmcsd_spi, mmcsd_crc16(ptr, size)); else { spi_xfer(mmcsd_spi, 0xFF); spi_xfer(mmcsd_spi, 0xFF); } // get the error code back from the card; "data accepted" is 0bXXX00101 ec = mmcsd_get_r1(); if(ec & 0x0A) { mmcsd_deselect(); return ec; } // wait for the line to go back high, this indicates that the write is complete while(spi_xfer(mmcsd_spi, 0xFF) == 0); mmcsd_deselect(); return MMCSD_GOODEC; } MMCSD_err mmcsd_go_idle_state(void) { mmcsd_send_cmd(GO_IDLE_STATE, 0); return mmcsd_get_r1(); } MMCSD_err mmcsd_send_op_cond(void) { mmcsd_send_cmd(SEND_OP_COND, 0); return mmcsd_get_r1(); } MMCSD_err mmcsd_send_if_cond(int r7[]) { mmcsd_send_cmd(SEND_IF_COND, 0x45A); return mmcsd_get_r7(r7); } MMCSD_err mmcsd_print_csd() { int buf[16], i, r1; // MMCs don't support this command if(g_card_type == MMC) return MMCSD_PARAM_ERR; mmcsd_select(); mmcsd_send_cmd(SEND_CSD, 0); r1 = mmcsd_get_r1(); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } r1 = mmcsd_wait_for_token(DATA_START_TOKEN); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } for(i = 0; i < 16; i++) buf[i] = spi_xfer(mmcsd_spi, 0xFF); mmcsd_deselect(); printf("\r\nCSD_STRUCTURE: %X", (buf[0] & 0x0C) >> 2); printf("\r\nTAAC: %X", buf[1]); printf("\r\nNSAC: %X", buf[2]); printf("\r\nTRAN_SPEED: %X", buf[3]); printf("\r\nCCC: %lX", (make16(buf[4], buf[5]) & 0xFFF0) >> 4); printf("\r\nREAD_BL_LEN: %X", buf[5] & 0x0F); printf("\r\nREAD_BL_PARTIAL: %X", (buf[6] & 0x80) >> 7); printf("\r\nWRITE_BLK_MISALIGN: %X", (buf[6] & 0x40) >> 6); printf("\r\nREAD_BLK_MISALIGN: %X", (buf[6] & 0x20) >> 5); printf("\r\nDSR_IMP: %X", (buf[6] & 0x10) >> 4); printf("\r\nC_SIZE: %lX", (((buf[6] & 0x03) << 10) | (buf[7] << 2) | ((buf[8] & 0xC0) >> 6))); printf("\r\nVDD_R_CURR_MIN: %X", (buf[8] & 0x38) >> 3); printf("\r\nVDD_R_CURR_MAX: %X", buf[8] & 0x07); printf("\r\nVDD_W_CURR_MIN: %X", (buf[9] & 0xE0) >> 5); printf("\r\nVDD_W_CURR_MAX: %X", (buf[9] & 0x1C) >> 2); printf("\r\nC_SIZE_MULT: %X", ((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7)); printf("\r\nERASE_BLK_EN: %X", (buf[10] & 0x40) >> 6); printf("\r\nSECTOR_SIZE: %X", ((buf[10] & 0x3F) << 1) | ((buf[11] & 0x80) >> 7)); printf("\r\nWP_GRP_SIZE: %X", buf[11] & 0x7F); printf("\r\nWP_GRP_ENABLE: %X", (buf[12] & 0x80) >> 7); printf("\r\nR2W_FACTOR: %X", (buf[12] & 0x1C) >> 2); printf("\r\nWRITE_BL_LEN: %X", ((buf[12] & 0x03) << 2) | ((buf[13] & 0xC0) >> 6)); printf("\r\nWRITE_BL_PARTIAL: %X", (buf[13] & 0x20) >> 5); printf("\r\nFILE_FORMAT_GRP: %X", (buf[14] & 0x80) >> 7); printf("\r\nCOPY: %X", (buf[14] & 0x40) >> 6); printf("\r\nPERM_WRITE_PROTECT: %X", (buf[14] & 0x20) >> 5); printf("\r\nTMP_WRITE_PROTECT: %X", (buf[14] & 0x10) >> 4); printf("\r\nFILE_FORMAT: %X", (buf[14] & 0x0C) >> 2); printf("\r\nCRC: %X", buf[15]); return r1; } MMCSD_err mmcsd_print_cid() { int buf[16], i, r1; // MMCs don't support this command if(g_card_type == MMC) return MMCSD_PARAM_ERR; mmcsd_select(); mmcsd_send_cmd(SEND_CID, 0); r1 = mmcsd_get_r1(); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } r1 = mmcsd_wait_for_token(DATA_START_TOKEN); if(r1 != MMCSD_GOODEC) { mmcsd_deselect(); return r1; } for(i = 0; i < 16; i++) buf[i] = spi_xfer(mmcsd_spi, 0xFF); mmcsd_deselect(); printf("\r\nManufacturer ID: %X", buf[0]); printf("\r\nOEM/Application ID: %c%c", buf[1], buf[2]); printf("\r\nOEM/Application ID: %c%c%c%c%c", buf[3], buf[4], buf[5], buf[6], buf[7]); printf("\r\nProduct Revision: %X", buf[8]); printf("\r\nSerial Number: %X%X%X%X", buf[9], buf[10], buf[11], buf[12]); printf("\r\nManufacturer Date Code: %X%X", buf[13] & 0x0F, buf[14]); printf("\r\nCRC-7 Checksum: %X", buf[15]); return r1; } MMCSD_err mmcsd_sd_status(int r2[]) { int i; mmcsd_select(); mmcsd_send_cmd(APP_CMD, 0); r2[0]=mmcsd_get_r1(); mmcsd_deselect(); mmcsd_select(); mmcsd_send_cmd(SD_STATUS, 0); for(i = 0; i < 64; i++) spi_xfer(mmcsd_spi, 0xFF); mmcsd_deselect(); return mmcsd_get_r2(r2); } MMCSD_err mmcsd_send_status(int r2[]) { mmcsd_send_cmd(SEND_STATUS, 0); return mmcsd_get_r2(r2); } MMCSD_err mmcsd_set_blocklen(int32 blocklen) { mmcsd_send_cmd(SET_BLOCKLEN, blocklen); return mmcsd_get_r1(); } MMCSD_err mmcsd_read_single_block(int32 address) { mmcsd_send_cmd(READ_SINGLE_BLOCK, address); return mmcsd_get_r1(); } MMCSD_err mmcsd_write_single_block(int32 address) { mmcsd_send_cmd(WRITE_BLOCK, address); return mmcsd_get_r1(); } MMCSD_err mmcsd_sd_send_op_cond(void) { mmcsd_send_cmd(SD_SEND_OP_COND, 0); return mmcsd_get_r1(); } MMCSD_err mmcsd_app_cmd(void) { mmcsd_send_cmd(APP_CMD, 0); return mmcsd_get_r1(); } MMCSD_err mmcsd_read_ocr(int r3[]) { mmcsd_send_cmd(READ_OCR, 0); return mmcsd_get_r3(r3); } MMCSD_err mmcsd_crc_on_off(int1 crc_enabled) { mmcsd_send_cmd(CRC_ON_OFF, crc_enabled); g_CRC_enabled = crc_enabled; return mmcsd_get_r1(); } MMCSD_err mmcsd_send_cmd(int cmd, int32 arg) { int packet[6]; // the entire command, argument, and crc in one variable // construct the packet // every command on an SD card is or'ed with 0x40 packet[0] = cmd | 0x40; packet[1] = make8(arg, 3); packet[2] = make8(arg, 2); packet[3] = make8(arg, 1); packet[4] = make8(arg, 0); // calculate the crc if needed if(g_CRC_enabled) packet[5] = mmcsd_crc7(packet, 5); else packet[5] = 0xFF; // transfer the command and argument, with an extra 0xFF hacked in there spi_xfer(mmcsd_spi, packet[0]); spi_xfer(mmcsd_spi, packet[1]); spi_xfer(mmcsd_spi, packet[2]); spi_xfer(mmcsd_spi, packet[3]); spi_xfer(mmcsd_spi, packet[4]); spi_xfer(mmcsd_spi, packet[5]); return MMCSD_GOODEC; } MMCSD_err mmcsd_get_r1(void) { int response = 0, // place to hold the response coming back from the SPI line timeout = 0xFF; // maximum amount loops to wait for idle before getting impatient and leaving the function with an error code // loop until timeout == 0 while(timeout) { // read what's on the SPI line // the SD/MMC requires that you leave the line high when you're waiting for data from it response = spi_xfer(mmcsd_spi, 0xFF); // check to see if we got a response if(response != 0xFF) { // fill in the response that we got and leave the function return response; } // wait for a little bit longer timeout--; } // for some reason, we didn't get a response back from the card // return the proper error codes return RESP_TIMEOUT; } MMCSD_err mmcsd_get_r2(int r2[]) { r2[1] = mmcsd_get_r1(); r2[0] = spi_xfer(mmcsd_spi, 0xFF); return 0; } MMCSD_err mmcsd_get_r3(int r3[]) { return mmcsd_get_r7(r3); } MMCSD_err mmcsd_get_r7(int r7[]) { int i; // counter for loop // the top byte of r7 is r1 r7[4]=mmcsd_get_r1(); // fill in the other 4 bytes for(i = 0; i < 4; i++) r7[3 - i] = spi_xfer(mmcsd_spi, 0xFF); return r7[4]; } MMCSD_err mmcsd_wait_for_token(int token) { MMCSD_err r1; // get a token r1 = mmcsd_get_r1(); // check to see if the token we recieved was the one that we were looking for if(r1 == token) return MMCSD_GOODEC; // if that wasn't right, return the error return r1; } unsigned int8 mmcsd_crc7(char *data, unsigned int8 length) { unsigned int8 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; } shift_left(&crc, 1, 1); // MMC card stores the result in the top 7 bits so shift them left 1 // Should shift in a 1 not a 0 as one of the cards I have won't work otherwise return crc; } unsigned int16 mmcsd_crc16(char *data, unsigned int8 length) { unsigned int8 i, ibit, c; unsigned int16 crc; crc = 0x0000; // Set initial value for (i = 0; i < length; i++, data++) { c = *data; for (ibit = 0; ibit < 8; ibit++) { crc = crc << 1; if ((c ^ crc) & 0x8000) crc = crc ^ 0x1021; // ^ is XOR c = c << 1; } crc = crc & 0x7FFF; } shift_left(&crc, 2, 1); // MMC card stores the result in the top 7 bits so shift them left 1 // Should shift in a 1 not a 0 as one of the cards I have won't work otherwise return crc; } void mmcsd_select() { output_low(MMCSD_PIN_SELECT); } void mmcsd_deselect() { spi_xfer(mmcsd_spi, 0xFF); output_high(MMCSD_PIN_SELECT); } MMCSD_err mmcsd_load_buffer(void) { g_MMCSDBufferChanged = FALSE; return(mmcsd_read_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE, g_mmcsd_buffer)); } MMCSD_err mmcsd_flush_buffer(void) { if (g_MMCSDBufferChanged) { g_MMCSDBufferChanged = FALSE; return(mmcsd_write_block(g_mmcsdBufferAddress, MMCSD_MAX_BLOCK_SIZE, g_mmcsd_buffer)); } return(0); //ok } MMCSD_err mmcsd_move_buffer(int32 new_addr) { MMCSD_err ec = MMCSD_GOODEC; int32 //cur_block, new_block; // make sure we're still on the same block //cur_block = g_mmcsdBufferAddress - (g_mmcsdBufferAddress % MMCSD_MAX_BLOCK_SIZE); new_block = new_addr - (new_addr % MMCSD_MAX_BLOCK_SIZE); //if(cur_block != new_block) if(g_mmcsdBufferAddress != new_block) { // dump the old buffer if (g_MMCSDBufferChanged) { ec = mmcsd_flush_buffer(); if(ec != MMCSD_GOODEC) return ec; g_MMCSDBufferChanged = FALSE; } // figure out the best place for a block g_mmcsdBufferAddress = new_block; // load up a new buffer ec = mmcsd_load_buffer(); } return ec; } MMCSD_err mmcsd_read_byte(int32 addr, char* data) { MMCSD_err ec; ec = mmcsd_move_buffer(addr); if(ec != MMCSD_GOODEC) { return ec; } *data = g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE]; return MMCSD_GOODEC; } MMCSD_err mmcsd_write_byte(int32 addr, char data) { MMCSD_err ec; ec = mmcsd_move_buffer(addr); if(ec != MMCSD_GOODEC) return ec; g_mmcsd_buffer[addr % MMCSD_MAX_BLOCK_SIZE] = data; g_MMCSDBufferChanged = TRUE; return MMCSD_GOODEC; } #endif