Skip to content

Instantly share code, notes, and snippets.

@mazurio
Created March 10, 2014 21:53
Show Gist options
  • Save mazurio/9475259 to your computer and use it in GitHub Desktop.
Save mazurio/9475259 to your computer and use it in GitHub Desktop.
/////////////////////////////////////////////////////////////////////////
//// 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 ////
//// ////
/////////////////////
#include "stdint.h"
#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, MODE=0, 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 ///
/// ///
////////////////////////
uint8_t g_mmcsd_buffer[MMCSD_MAX_BLOCK_SIZE];
int1 g_CRC_enabled;
int1 g_MMCSDBufferChanged;
uint32_t g_mmcsdBufferAddress;
uint32_t g_mmcsdPartitionOffset;
enum _card_type{SD, MMC} g_card_type;
/////////////////////////////
//// ////
//// Function Prototypes ////
//// ////
/////////////////////////////
MMCSD_err mmcsd_init();
MMCSD_err mmcsd_read_data(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_read_block(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_write_data(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_write_block(uint32_t address, uint16_t size, uint8_t* ptr);
MMCSD_err mmcsd_go_idle_state(void);
MMCSD_err mmcsd_send_op_cond(void);
MMCSD_err mmcsd_send_if_cond(uint8_t r7[]);
MMCSD_err mmcsd_print_csd();
MMCSD_err mmcsd_print_cid();
MMCSD_err mmcsd_sd_status(uint8_t r2[]);
MMCSD_err mmcsd_send_status(uint8_t r2[]);
MMCSD_err mmcsd_set_blocklen(uint32_t blocklen);
MMCSD_err mmcsd_read_single_block(uint32_t address);
MMCSD_err mmcsd_write_single_block(uint32_t address);
MMCSD_err mmcsd_sd_send_op_cond(void);
MMCSD_err mmcsd_app_cmd(void);
MMCSD_err mmcsd_read_ocr(uint8_t* r1);
MMCSD_err mmcsd_crc_on_off(int1 crc_enabled);
MMCSD_err mmcsd_send_cmd(uint8_t cmd, uint32_t arg);
MMCSD_err mmcsd_get_r1(void);
MMCSD_err mmcsd_get_r2(uint8_t r2[]);
MMCSD_err mmcsd_get_r3(uint8_t r3[]);
MMCSD_err mmcsd_get_r7(uint8_t r7[]);
MMCSD_err mmcsd_wait_for_token(uint8_t token);
uint8_t mmcsd_crc7(char *data, uint8_t length);
uint16_t mmcsd_crc16(char *data, uint8_t 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(uint32_t new_addr);
MMCSD_err mmcsd_read_byte(uint32_t addr, char* data);
MMCSD_err mmcsd_write_byte(uint32_t addr, char data);
//////////////////////////////////
//// ////
//// Function Implementations ////
//// ////
//////////////////////////////////
void mmcsd_check_part(uint16_t off)
{
if (g_mmcsd_buffer[off + 0] == 0x80)
{
// active partition
uint8_t t;
t = g_mmcsd_buffer[off + 4];
if (t == 0x04 || t == 0x06 || t == 0x0B)
{
// FAT16 or FAT32 partition
g_mmcsdPartitionOffset = make32(
g_mmcsd_buffer[off + 11], g_mmcsd_buffer[off + 10],
g_mmcsd_buffer[off + 9], g_mmcsd_buffer[off + 8]) * MMCSD_MAX_BLOCK_SIZE;
}
}
}
MMCSD_err mmcsd_init()
{
uint8_t
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();
g_mmcsdPartitionOffset = 0;
mmcsd_check_part(0x1EE);
mmcsd_check_part(0x1DE);
mmcsd_check_part(0x1CE);
mmcsd_check_part(0x1BE);
return r1;
}
MMCSD_err mmcsd_read_data(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err r1;
uint16_t 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(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t 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(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t 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(uint32_t address, uint16_t size, uint8_t* ptr)
{
MMCSD_err ec;
uint16_t 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(uint8_t r7[])
{
mmcsd_send_cmd(SEND_IF_COND, 0x45A);
return mmcsd_get_r7(r7);
}
MMCSD_err mmcsd_print_csd()
{
uint8_t
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()
{
uint8_t
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(uint8_t r2[])
{
uint8_t 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(uint8_t r2[])
{
mmcsd_send_cmd(SEND_STATUS, 0);
return mmcsd_get_r2(r2);
}
MMCSD_err mmcsd_set_blocklen(uint32_t blocklen)
{
mmcsd_send_cmd(SET_BLOCKLEN, blocklen);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_read_single_block(uint32_t address)
{
mmcsd_send_cmd(READ_SINGLE_BLOCK, address);
return mmcsd_get_r1();
}
MMCSD_err mmcsd_write_single_block(uint32_t 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(uint8_t cmd, uint32_t arg)
{
uint8_t 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]);
//! spi_write2(packet[0]);
//! spi_write2(packet[1]);
//! spi_write2(packet[2]);
//! spi_write2(packet[3]);
//! spi_write2(packet[4]);
//! spi_write2(packet[5]);
return MMCSD_GOODEC;
}
MMCSD_err mmcsd_get_r1(void)
{
uint8_t
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);
//response = spi_xfer(mmcsd_spi, 0x00);//leave the line idle
// 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(uint8_t r2[])
{
r2[1] = mmcsd_get_r1();
r2[0] = spi_xfer(mmcsd_spi, 0xFF);
return 0;
}
MMCSD_err mmcsd_get_r3(uint8_t r3[])
{
return mmcsd_get_r7(r3);
}
MMCSD_err mmcsd_get_r7(uint8_t r7[])
{
uint8_t 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(uint8_t 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,uint8_t length)
{
uint8_t 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;
}
uint16_t mmcsd_crc16(char *data, uint8_t length)
{
uint8_t i, ibit, c;
uint16_t 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(uint32_t new_addr)
{
MMCSD_err ec = MMCSD_GOODEC;
uint32_t
//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(uint32_t 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(uint32_t 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment