LPC2148 on LOGOMATIC, use SPI1 for SD card

Hi, I try to use the SPI1 port to write the data on a deported SD card in place of the on-board micro SD (on SPI0) (http://www.parallax.com/tabid/768/txtSe … fault.aspx).

For that, I change into sd_raw_config.h the correspondent PINSEL and IODIR registers and make some modification in sd_raw.c but I can’t detect the SD card.

Does someone have an idea? I know that this port is more complicate to configure.

these files are here under

sd_raw_config.h

sd_raw.c

best regards,

philippe

===========================================================

sd_raw_config.h

===========================================================

/* This program is free software; you can redistribute it and/or modify

  • it under the terms of the GNU General Public License version 2 as

  • published by the Free Software Foundation.

*/

//#ifndef SD_RAW_CONFIG_H

//#define SD_RAW_CONFIG_H

//#define SS_PORT_0

#define SS_PORT_1

#define SPI_SS_IODIR IODIR0

#define SPI_SS_IOCLR IOCLR0

#define SPI_SS_IOSET IOSET0

#define SPI_SS_IOPIN IOPIN0

//SPI Chip Select Defines for SD Access

#ifdef SS_PORT_0

#define SPI_SS_PIN 7

#define configure_pin_mosi() PINSEL0 |= (1 << 12)

#define configure_pin_miso() PINSEL0 |= (1 << 10)

#define configure_pin_sck() PINSEL0 |= (1 << 8)

#endif

#ifdef SS_PORT_1

#define SPI_SS_PIN 20

#define configure_pin_mosi() PINSEL1 |= (1 << 7)

#define configure_pin_miso() PINSEL1 |= (1 << 5)

#define configure_pin_sck() PINSEL1 |= (1 << 3)

#endif

#define configure_pin_ss() SPI_SS_IODIR |= (1<<SPI_SS_PIN)

#define select_card() SPI_SS_IOCLR |= (1<<SPI_SS_PIN)

#define unselect_card() SPI_SS_IOSET |= (1<<SPI_SS_PIN)

#define configure_pin_available() SPI_SS_IODIR &= ~(1<<SPI_SS_PIN)

#define configure_pin_locked() if(1)

#define get_pin_available() (!((SPI_SS_IOPIN&(1<<SPI_SS_PIN))>>SPI_SS_PIN))

#define get_pin_locked() (0)

/**

  • \addtogroup sd_raw

  • @{

*/

/**

  • \file

  • MMC/SD support configuration.

*/

/**

  • \ingroup sd_raw_config

  • Controls MMC/SD write support.

  • Set to 1 to enable MMC/SD write support, set to 0 to disable it.

*/

#define SD_RAW_WRITE_SUPPORT 1

/**

  • \ingroup sd_raw_config

  • Controls MMC/SD write buffering.

  • Set to 1 to buffer write accesses, set to 0 to disable it.

  • \note This option has no effect when SD_RAW_WRITE_SUPPORT is 0.

*/

#define SD_RAW_WRITE_BUFFERING 1

/**

  • \ingroup sd_raw_config

  • Controls MMC/SD access buffering.

  • Set to 1 to save static RAM, but be aware that you will

  • lose performance.

  • \note When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will

  • be reset to 0.

*/

#define SD_RAW_SAVE_RAM 1

/**

  • @}

*/

/* configuration checks */

#if SD_RAW_WRITE_SUPPORT

#undef SD_RAW_SAVE_RAM

#define SD_RAW_SAVE_RAM 0

#else

#undef SD_RAW_WRITE_BUFFERING

#define SD_RAW_WRITE_BUFFERING 0

#endif

//#endif

===========================================================

sd_raw.c

===========================================================

/* This program is free software; you can redistribute it and/or modify

  • it under the terms of the GNU General Public License version 2 as

  • published by the Free Software Foundation.

*/

#include <stdio.h>

#include <string.h>

#include “LPC214x.h”

#include “serial.h”

#include “rprintf.h”

#include “sd_raw.h”

/**

  • \addtogroup sd_raw MMC/SD card raw access

  • This module implements read and write access to MMC and

  • SD cards. It serves as a low-level driver for the higher

  • level modules such as partition and file system access.

  • @{

*/

/**

  • \file

  • MMC/SD raw access implementation.

  • \author Roland Riegel

*/

/**

  • \addtogroup sd_raw_config MMC/SD configuration

  • Preprocessor defines to configure the MMC/SD support.

*/

/**

  • @}

*/

/* commands available in SPI mode */

/* CMD0: response R1 */

#define CMD_GO_IDLE_STATE 0x00

/* CMD1: response R1 */

#define CMD_SEND_OP_COND 0x01

/* CMD9: response R1 */

#define CMD_SEND_CSD 0x09

/* CMD10: response R1 */

#define CMD_SEND_CID 0x0a

/* CMD12: response R1 */

#define CMD_STOP_TRANSMISSION 0x0c

/* CMD13: response R2 */

#define CMD_SEND_STATUS 0x0d

/* CMD16: arg0[31:0]: block length, response R1 */

#define CMD_SET_BLOCKLEN 0x10

/* CMD17: arg0[31:0]: data address, response R1 */

#define CMD_READ_SINGLE_BLOCK 0x11

/* CMD18: arg0[31:0]: data address, response R1 */

#define CMD_READ_MULTIPLE_BLOCK 0x12

/* CMD24: arg0[31:0]: data address, response R1 */

#define CMD_WRITE_SINGLE_BLOCK 0x18

/* CMD25: arg0[31:0]: data address, response R1 */

#define CMD_WRITE_MULTIPLE_BLOCK 0x19

/* CMD27: response R1 */

#define CMD_PROGRAM_CSD 0x1b

/* CMD28: arg0[31:0]: data address, response R1b */

#define CMD_SET_WRITE_PROT 0x1c

/* CMD29: arg0[31:0]: data address, response R1b */

#define CMD_CLR_WRITE_PROT 0x1d

/* CMD30: arg0[31:0]: write protect data address, response R1 */

#define CMD_SEND_WRITE_PROT 0x1e

/* CMD32: arg0[31:0]: data address, response R1 */

#define CMD_TAG_SECTOR_START 0x20

/* CMD33: arg0[31:0]: data address, response R1 */

#define CMD_TAG_SECTOR_END 0x21

/* CMD34: arg0[31:0]: data address, response R1 */

#define CMD_UNTAG_SECTOR 0x22

/* CMD35: arg0[31:0]: data address, response R1 */

#define CMD_TAG_ERASE_GROUP_START 0x23

/* CMD36: arg0[31:0]: data address, response R1 */

#define CMD_TAG_ERASE_GROUP_END 0x24

/* CMD37: arg0[31:0]: data address, response R1 */

#define CMD_UNTAG_ERASE_GROUP 0x25

/* CMD38: arg0[31:0]: stuff bits, response R1b */

#define CMD_ERASE 0x26

/* CMD42: arg0[31:0]: stuff bits, response R1b */

#define CMD_LOCK_UNLOCK 0x2a

/* CMD58: response R3 */

#define CMD_READ_OCR 0x3a

/* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */

#define CMD_CRC_ON_OFF 0x3b

/* command responses */

/* R1: size 1 byte */

#define R1_IDLE_STATE 0

#define R1_ERASE_RESET 1

#define R1_ILL_COMMAND 2

#define R1_COM_CRC_ERR 3

#define R1_ERASE_SEQ_ERR 4

#define R1_ADDR_ERR 5

#define R1_PARAM_ERR 6

/* R1b: equals R1, additional busy bytes */

/* R2: size 2 bytes */

#define R2_CARD_LOCKED 0

#define R2_WP_ERASE_SKIP 1

#define R2_ERR 2

#define R2_CARD_ERR 3

#define R2_CARD_ECC_FAIL 4

#define R2_WP_VIOLATION 5

#define R2_INVAL_ERASE 6

#define R2_OUT_OF_RANGE 7

#define R2_CSD_OVERWRITE 7

#define R2_IDLE_STATE (R1_IDLE_STATE + 8)

#define R2_ERASE_RESET (R1_ERASE_RESET + 8)

#define R2_ILL_COMMAND (R1_ILL_COMMAND + 8)

#define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8)

#define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8)

#define R2_ADDR_ERR (R1_ADDR_ERR + 8)

#define R2_PARAM_ERR (R1_PARAM_ERR + 8)

/* R3: size 5 bytes */

#define R3_OCR_MASK (0xffffffffUL)

#define R3_IDLE_STATE (R1_IDLE_STATE + 32)

#define R3_ERASE_RESET (R1_ERASE_RESET + 32)

#define R3_ILL_COMMAND (R1_ILL_COMMAND + 32)

#define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32)

#define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32)

#define R3_ADDR_ERR (R1_ADDR_ERR + 32)

#define R3_PARAM_ERR (R1_PARAM_ERR + 32)

/* Data Response: size 1 byte */

#define DR_STATUS_MASK 0x0e

#define DR_STATUS_ACCEPTED 0x05

#define DR_STATUS_CRC_ERR 0x0a

#define DR_STATUS_WRITE_ERR 0x0c

#if !SD_RAW_SAVE_RAM

/* static data buffer for acceleration */

static unsigned char raw_block[512];

/* offset where the data within raw_block lies on the card */

static unsigned int raw_block_address;

#if SD_RAW_WRITE_BUFFERING

/* flag to remember if raw_block was written to the card */

static unsigned char raw_block_written;

#endif

#endif

/* private helper functions */

static void sd_raw_send_byte(unsigned char b);

static unsigned char sd_raw_rec_byte(void);

static unsigned char sd_raw_send_command_r1(unsigned char command, unsigned int arg);

//static unsigned short sd_raw_send_command_r2(unsigned char command, unsigned int arg);

/**

  • \ingroup sd_raw

  • Initializes memory card communication.

  • \returns 0 on failure, 1 on success.

*/

unsigned char sd_raw_init()

{

/* enable inputs for reading card status */

/* configure_pin_available();*/

/* configure_pin_locked();*/

/* enable outputs for MOSI, SCK, SS, input for MISO */

rprintf_devopen(putc_serial0); //Open up serial port 0 for debugging

rprintf(" ;PS0=%x;PS1=%x;IOD=%x;IOP=%x;SPI=%d\r\n",PINSEL0,PINSEL1,IODIR0,IOPIN0,SPI_SS_PIN);

configure_pin_mosi();

rprintf(“confi_pin_mosi ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

configure_pin_miso();

rprintf(“confi_pin_miso ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

configure_pin_sck();

//IF (SPI_SS_PIN == 20) {SPI_SS_IOSET |= (1<<17);}

rprintf(“confi_pin_sck ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

configure_pin_ss();

rprintf(“confi_pin_ss ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

unselect_card();

rprintf(“unselect_card ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

/* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */

#ifdef SS_PORT_0

S0SPCCR = 0x96; /* Set frequency to 400kHz */

//S0SPCR = 0x38; //SPI Master, CPHA second clck, CPOL SCK active low

S0SPCR = 0x20; //SPI Master, CPHA first clck, CPOL SCK active high

rprintf(" ;S0SPCR=%x;S0SPCCR=%x\r\n",S0SPCR,S0SPCCR);

#endif

#ifdef SS_PORT_1

SSPCPSR= 0x02; // prédiviseur

SSPCR0 = 0x4AC7; // configuré comme SPI, first clk edge, active high,

SSPCR1 = 0x0000; // master and not loopback

rprintf(" ;SSPCR0=%x;SSPCR1=%x;SSPCPSR=%x\r\n",SSPCR0,SSPCR1,SSPCPSR);

#endif

/* initialization procedure */

if(!sd_raw_available()) //no reg to modify

{

rprintf(“SD RAW NOT AVAILABLE\n\r”);

return 0;

}

else

{

rprintf(“SD RAW AVAILABLE\n\r”);

}

configure_pin_ss();

rprintf(“config_pin_ss ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

unselect_card();

rprintf(“unselect_card ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

unsigned short i;

/* card needs 74 cycles minimum to start up */

for(i = 0; i < 10; ++i)

{

/* wait 8 clock cycles */

rprintf(“%d”,i);

sd_raw_rec_byte();

}

/* address card */

select_card();

rprintf(“\r\nselect_card ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

/* reset card */

unsigned char response;

for(i = 0; ; ++i)

{

response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);

if(response == (1 << R1_IDLE_STATE))

break;

if(i == 0x1ff)

{

unselect_card();

return 0;

}

}

rprintf(“response GO_IDLE_STATE: %x i=%d\n\r”,response,i);

/* wait for card to get ready */

for(i = 0; ; ++i)

{

response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0);

if(!(response & (1 << R1_IDLE_STATE)))

break;

if(i == 0x7fff)

{

unselect_card();

return 0;

}

}

rprintf(“response SEND_OP_COND: %x i=%d\n\r”,response,i);

/* set block size to 512 bytes */

if(sd_raw_send_command_r1(CMD_SET_BLOCKLEN, 512))

{

unselect_card();

rprintf(“BLOCK SIZE SET ERR \n\r”);

return 0;

}

else

{

rprintf(“BLOCK SIZE SET\n\r”);

}

/* deaddress card */

unselect_card();

/* switch to highest SPI frequency possible */

S0SPCCR = 60; /* ~1MHz-- potentially can be faster */

#if !SD_RAW_SAVE_RAM

/* the first block is likely to be accessed first, so precache it here */

raw_block_address = 0xffffffff;

#if SD_RAW_WRITE_BUFFERING

raw_block_written = 1;

#endif

if(!sd_raw_read(0, raw_block, sizeof(raw_block)))

{

rprintf(“sd_raw_read borks\n\r”);

return 0;

}

#endif

return 1;

}

/**

  • \ingroup sd_raw

  • Checks wether a memory card is located in the slot.

  • \returns 1 if the card is available, 0 if it is not.

*/

unsigned char sd_raw_available() //NO REGISTRE TO MODIFY

{

unsigned int i;

configure_pin_available();

rprintf(“conf_pin_available;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

for(i=0;i<100000;i++);

i = get_pin_available();

configure_pin_ss();

rprintf(“configure_pin_ss ;PS0=%x;PS1=%x;IOD=%x;IOP=%x\r\n”,PINSEL0,PINSEL1,IODIR0,IOPIN0);

return i == 0x00;

}

/**

  • \ingroup sd_raw

  • Checks wether the memory card is locked for write access.

  • \returns 1 if the card is locked, 0 if it is not.

*/

unsigned char sd_raw_locked()

{

return get_pin_locked() == 0x00;

}

/**

  • \ingroup sd_raw

  • Sends a raw byte to the memory card.

  • \param[in] b The byte to sent.

  • \see sd_raw_rec_byte

*/

void sd_raw_send_byte(unsigned char byteToSend) // S0SPDR S0SPSR

{

#ifdef SS_PORT_0

S0SPDR = byteToSend;

/* wait for byte to be shifted out */

while(!(S0SPSR & 0x80));

#endif

#ifdef SS_PORT_1

SSPDR = byteToSend;

/* wait for byte to be shifted out */

while(!(SSPSR & 0x00));

#endif

}

/**

  • \ingroup sd_raw

  • Receives a raw byte from the memory card.

  • \returns The byte which should be read.

  • \see sd_raw_send_byte

*/

unsigned char sd_raw_rec_byte(void) //S0SPDR

{

/* send dummy data for receiving some */

#ifdef SS_PORT_0

S0SPDR = 0xff;

while(!(S0SPSR & 0x80));

return S0SPDR;

#endif

#ifdef SS_PORT_1

SSPDR = 0xffff;

while(!(SSPSR & 0x00));

return SSPDR;

#endif

}

/**

  • \ingroup sd_raw

  • Send a command to the memory card which responses with a R1 response.

  • \param[in] command The command to send.

  • \param[in] arg The argument for command.

  • \returns The command answer.

*/

unsigned char sd_raw_send_command_r1(unsigned char command, unsigned int arg)

{

unsigned char response;

unsigned char i;

/* wait some clock cycles */

sd_raw_rec_byte();

/* send command via SPI */

sd_raw_send_byte(0x40 | command);

sd_raw_send_byte((arg >> 24) & 0xff);

sd_raw_send_byte((arg >> 16) & 0xff);

sd_raw_send_byte((arg >> 8) & 0xff);

sd_raw_send_byte((arg >> 0) & 0xff);

sd_raw_send_byte((command == CMD_GO_IDLE_STATE) ? 0x95 : 0xff);

/* receive response */

for(i = 0; i < 10; ++i)

{

response = sd_raw_rec_byte();

if(response != 0xff)

break;

}

return response;

}

/**

  • \ingroup sd_raw

  • Send a command to the memory card which responses with a R2 response.

  • \param[in] command The command to send.

  • \param[in] arg The argument for command.

  • \returns The command answer.

*/

/*

unsigned short sd_raw_send_command_r2(unsigned char command, unsigned int arg)

{

unsigned short response;

unsigned char i;

// wait some clock cycles

sd_raw_rec_byte();

// send command via SPI

sd_raw_send_byte(0x40 | command);

sd_raw_send_byte((arg >> 24) & 0xff);

sd_raw_send_byte((arg >> 16) & 0xff);

sd_raw_send_byte((arg >> 8) & 0xff);

sd_raw_send_byte((arg >> 0) & 0xff);

sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff);

// receive response

for(i = 0; i < 10; ++i)

{

response = sd_raw_rec_byte();

if(response != 0xff)

break;

}

response <<= 8;

response |= sd_raw_rec_byte();

return response;

}

*/

/**

  • \ingroup sd_raw

  • Reads raw data from the card.

  • \param[in] offset The offset from which to read.

  • \param[out] buffer The buffer into which to write the data.

  • \param[in] length The number of bytes to read.

  • \returns 0 on failure, 1 on success.

  • \see sd_raw_read_interval, sd_raw_write

*/

unsigned char sd_raw_read(unsigned int offset, unsigned char* buffer, unsigned short length)

{

unsigned int block_address;

unsigned short block_offset;

unsigned short read_length;

while(length > 0)

{

/* determine byte count to read at once */

block_address = offset & 0xfffffe00;

block_offset = offset & 0x01ff;

read_length = 512 - block_offset; /* read up to block border */

if(read_length > length)

read_length = length;

#if !SD_RAW_SAVE_RAM

/* check if the requested data is cached */

if(block_address != raw_block_address)

#endif

{

#if SD_RAW_WRITE_BUFFERING

if(!raw_block_written)

{

if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))

return 0;

}

#endif

/* address card */

select_card();

/* send single block request */

if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address))

{

unselect_card();

return 0;

}

/* wait for data block (start byte 0xfe) */

while(sd_raw_rec_byte() != 0xfe);

#if SD_RAW_SAVE_RAM

/* read byte block */

unsigned short read_to = block_offset + read_length;

for(unsigned short i = 0; i < 512; ++i)

{

unsigned char b = sd_raw_rec_byte();

if(i >= block_offset && i < read_to)

*buffer++ = b;

}

#else

/* read byte block */

unsigned char* cache = raw_block;

unsigned short i;

for(i = 0; i < 512; ++i)

*cache++ = sd_raw_rec_byte();

raw_block_address = block_address;

memcpy(buffer, raw_block + block_offset, read_length);

buffer += read_length;

#endif

/* read crc16 */

sd_raw_rec_byte();

sd_raw_rec_byte();

/* deaddress card */

unselect_card();

/* let card some time to finish */

sd_raw_rec_byte();

}

#if !SD_RAW_SAVE_RAM

else

{

/* use cached data */

memcpy(buffer, raw_block + block_offset, read_length);

}

#endif

length -= read_length;

offset += read_length;

}

return 1;

}

/**

  • \ingroup sd_raw

  • Continuously reads units of \c interval bytes and calls a callback function.

  • This function starts reading at the specified offset. Every \c interval bytes,

  • it calls the callback function with the associated data buffer.

  • By returning zero, the callback may stop reading.

  • \note Within the callback function, you can not start another read or

  • write operation.

  • \note This function only works if the following conditions are met:

    • (offset - (offset % 512)) % interval == 0
    • length % interval == 0
  • \param[in] offset Offset from which to start reading.

  • \param[in] buffer Pointer to a buffer which is at least interval bytes in size.

  • \param[in] interval Number of bytes to read before calling the callback function.

  • \param[in] length Number of bytes to read altogether.

  • \param[in] callback The function to call every interval bytes.

  • \param[in] p An opaque pointer directly passed to the callback function.

  • \returns 0 on failure, 1 on success

  • \see sd_raw_read, sd_raw_write

*/

unsigned char sd_raw_read_interval(unsigned int offset, unsigned char* buffer, unsigned short interval, unsigned short length, sd_raw_interval_handler callback, void* p)

{

if(!buffer || interval == 0 || length < interval || !callback)

return 0;

#if !SD_RAW_SAVE_RAM

while(length >= interval)

{

/* as reading is now buffered, we directly

  • hand over the request to sd_raw_read()

*/

if(!sd_raw_read(offset, buffer, interval))

return 0;

if(!callback(buffer, offset, p))

break;

offset += interval;

length -= interval;

}

return 1;

#else

/* address card */

select_card();

unsigned short block_offset;

unsigned short read_length;

unsigned char* buffer_cur;

unsigned char finished = 0;

do

{

/* determine byte count to read at once */

block_offset = offset & 0x01ff;

read_length = 512 - block_offset;

/* send single block request */

if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00))

{

unselect_card();

return 0;

}

/* wait for data block (start byte 0xfe) */

while(sd_raw_rec_byte() != 0xfe);

unsigned short i;

/* read up to the data of interest */

for(i = 0; i < block_offset; ++i)

sd_raw_rec_byte();

/* read interval bytes of data and execute the callback */

do

{

if(read_length < interval || length < interval)

break;

buffer_cur = buffer;

for(i = 0; i < interval; ++i)

*buffer_cur++ = sd_raw_rec_byte();

if(!callback(buffer, offset + (512 - read_length), p))

{

finished = 1;

break;

}

read_length -= interval;

length -= interval;

}

while(read_length > 0 && length > 0);

/* read rest of data block */

while(read_length-- > 0)

sd_raw_rec_byte();

/* read crc16 */

sd_raw_rec_byte();

sd_raw_rec_byte();

if(length < interval)

break;

offset = (offset & 0xfffffe00) + 512;

}

while(!finished);

/* deaddress card */

unselect_card();

/* let card some time to finish */

sd_raw_rec_byte();

return 1;

#endif

}

/**

  • \ingroup sd_raw

  • Writes raw data to the card.

  • \note If write buffering is enabled, you might have to

  • call sd_raw_sync() before disconnecting the card

  • to ensure all remaining data has been written.

  • \param[in] offset The offset where to start writing.

  • \param[in] buffer The buffer containing the data to be written.

  • \param[in] length The number of bytes to write.

  • \returns 0 on failure, 1 on success.

  • \see sd_raw_read

*/

unsigned char sd_raw_write(unsigned int offset, const unsigned char* buffer, unsigned short length)

{

#if SD_RAW_WRITE_SUPPORT

if(get_pin_locked())

return 0;

unsigned int block_address;

unsigned short block_offset;

unsigned short write_length;

while(length > 0)

{

/* determine byte count to write at once */

block_address = offset & 0xfffffe00;

block_offset = offset & 0x01ff;

write_length = 512 - block_offset; /* write up to block border */

if(write_length > length)

write_length = length;

/* Merge the data to write with the content of the block.

  • Use the cached block if available.

*/

if(block_address != raw_block_address)

{

#if SD_RAW_WRITE_BUFFERING

if(!raw_block_written)

{

if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))

return 0;

}

#endif

if(block_offset || write_length < 512)

{

if(!sd_raw_read(block_address, raw_block, sizeof(raw_block)))

return 0;

}

raw_block_address = block_address;

}

if(buffer != raw_block)

{

memcpy(raw_block + block_offset, buffer, write_length);

#if SD_RAW_WRITE_BUFFERING

raw_block_written = 0;

if(length == write_length)

return 1;

#endif

}

buffer += write_length;

/* address card */

select_card();

/* send single block request */

if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address))

{

unselect_card();

return 0;

}

/* send start byte */

sd_raw_send_byte(0xfe);

/* write byte block */

unsigned char* cache = raw_block;

unsigned short i;

for(i = 0; i < 512; ++i)

sd_raw_send_byte(*cache++);

/* write dummy crc16 */

sd_raw_send_byte(0xff);

sd_raw_send_byte(0xff);

/* wait while card is busy */

while(sd_raw_rec_byte() != 0xff);

sd_raw_rec_byte();

/* deaddress card */

unselect_card();

length -= write_length;

offset += write_length;

#if SD_RAW_WRITE_BUFFERING

raw_block_written = 1;

#endif

}

return 1;

#else

return 0;

#endif

}

/**

  • \ingroup sd_raw

  • Writes the write buffer’s content to the card.

  • \note When write buffering is enabled, you should

  • call this function before disconnecting the

  • card to ensure all remaining data has been

  • written.

  • \returns 0 on failure, 1 on success.

  • \see sd_raw_write

*/

unsigned char sd_raw_sync()

{

#if SD_RAW_WRITE_SUPPORT

#if SD_RAW_WRITE_BUFFERING

if(raw_block_written)

return 1;

if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))

return 0;

#endif

return 1;

#else

return 0;

#endif

}

/**

  • \ingroup sd_raw

  • Reads informational data from the card.

  • This function reads and returns the card’s registers

  • containing manufacturing and status information.

  • \note: The information retrieved by this function is

  • not required in any way to operate on the card,

  • but it might be nice to display some of the data

  • to the user.

  • \param[in] info A pointer to the structure into which to save the information.

  • \returns 0 on failure, 1 on success.

*/

unsigned char sd_raw_get_info(struct sd_raw_info* info)

{

if(!info || !sd_raw_available())

return 0;

memset(info, 0, sizeof(*info));

select_card();

/* read cid register */

if(sd_raw_send_command_r1(CMD_SEND_CID, 0))

{

unselect_card();

return 0;

}

while(sd_raw_rec_byte() != 0xfe);

unsigned char i;

for(i = 0; i < 18; ++i)

{

unsigned char b = sd_raw_rec_byte();

switch(i)

{

case 0:

info->manufacturer = b;

break;

case 1:

case 2:

info->oem[i - 1] = b;

break;

case 3:

case 4:

case 5:

case 6:

case 7:

info->product[i - 3] = b;

break;

case 8:

info->revision = b;

break;

case 9:

case 10:

case 11:

case 12:

info->serial |= (unsigned int) b << ((12 - i) * 8);

break;

case 13:

info->manufacturing_year = b << 4;

break;

case 14:

info->manufacturing_year |= b >> 4;

info->manufacturing_month = b & 0x0f;

break;

}

}

/* read csd register */

unsigned char csd_read_bl_len = 0;

unsigned char csd_c_size_mult = 0;

unsigned short csd_c_size = 0;

if(sd_raw_send_command_r1(CMD_SEND_CSD, 0))

{

unselect_card();

return 0;

}

while(sd_raw_rec_byte() != 0xfe);

for(i = 0; i < 18; ++i)

{

unsigned char b = sd_raw_rec_byte();

switch(i)

{

case 5:

csd_read_bl_len = b & 0x0f;

break;

case 6:

csd_c_size = (unsigned short) (b & 0x03) << 8;

break;

case 7:

csd_c_size |= b;

csd_c_size <<= 2;

break;

case 8:

csd_c_size |= b >> 6;

++csd_c_size;

break;

case 9:

csd_c_size_mult = (b & 0x03) << 1;

break;

case 10:

csd_c_size_mult |= b >> 7;

info->capacity = (unsigned int) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2);

break;

case 14:

if(b & 0x40)

info->flag_copy = 1;

if(b & 0x20)

info->flag_write_protect = 1;

if(b & 0x10)

info->flag_write_protect_temp = 1;

info->format = (b & 0x0c) >> 2;

break;

}

}

unselect_card();

return 1;

}

void SDoff(void)

{

SPI_SS_IODIR &= ~(1<<SPI_SS_PIN);

PINSEL0 &= ~(0x1500);

}

//NES : 10-28-7

//Low-level formats a 512MB card

//Assumes many things

//You must pass this fuction 0xAA to get it to work (safety check)

char format_card(char make_sure)

{

#define MBR_LOCATION 0x00

#define BR_LOCATION (MBR_LOCATION+0x80000)

#define FAT_TABLE (BR_LOCATION + (0x200 * 512))

#define ROOT_DIR (BR_LOCATION + (0x0200 * 512) + (0x00F5 * 2 * 512))

//Safety check

if (make_sure != 0xAA) return 0;

int i;

unsigned char my_buff[512];

for(i = 0 ; i < 512 ; i++) my_buff = 0x00;

  • //Init SD card interface*

  • sd_raw_init();*

  • //Erase Master Boot record*

  • sd_raw_sync();*

  • sd_raw_write(MBR_LOCATION, my_buff, 512);*

  • //Erase Boot record*

  • sd_raw_sync();*

  • sd_raw_write(BR_LOCATION, my_buff, 512);*

  • //Erase FAT tables*

  • for(i = 0 ; i < 0x00F5 ; i++) //0x00F5 = 245 bytes : comes from byte 0x16 from Boot Record*

  • {*

  • sd_raw_sync();*
    sd_raw_write( (FAT_TABLE + (i*512)), my_buff, 512);

  • }*

  • //Write Master Boot Record*

  • #define PART1 0x01BE*

  • my_buff[PART1 + 0] = 0x00;*

  • my_buff[PART1 + 1] = 0x00;*

  • my_buff[PART1 + 2] = 0x01;*

  • my_buff[PART1 + 3] = 0x01;*

  • my_buff[PART1 + 4] = 0x06;*

  • my_buff[PART1 + 5] = 0x1F;*

  • my_buff[PART1 + 6] = 0xE0;*

  • my_buff[PART1 + 7] = 0xD3;*

  • my_buff[PART1 + 8] = 0x00;*

  • my_buff[PART1 + 9] = 0x04;*

  • my_buff[PART1 + 10] = 0x00;*

  • my_buff[PART1 + 11] = 0x00;*

  • my_buff[PART1 + 12] = 0x00;*

  • my_buff[PART1 + 13] = 0x4C;*

  • my_buff[PART1 + 14] = 0x0F;*

  • my_buff[510] = 0x55;*

  • my_buff[511] = 0xAA;*

  • sd_raw_sync();*

  • sd_raw_write(MBR_LOCATION, my_buff, 512);*

  • sd_raw_sync();*

  • //Write Boot Record*

  • #define BOOTRECORD1 0x80000*

  • my_buff[0] = 0xEB;*

  • my_buff[1] = 0xFE;*

  • my_buff[2] = 0x90;*

  • my_buff[12] = 0x02;*

  • my_buff[13] = 0x10;*

  • my_buff[14] = 0x16;*

  • my_buff[16] = 0x02;*

  • my_buff[18] = 0x02;*

  • my_buff[21] = 0xF8;*

  • my_buff[22] = 0xF5;*

  • my_buff[24] = 0x20;*

  • my_buff[26] = 0x20;*

  • my_buff[29] = 0x04;*

  • my_buff[33] = 0x4C;*

  • my_buff[34] = 0x0F;*

  • my_buff[38] = 0x29;*

  • my_buff[54] = 0x46;*

  • my_buff[55] = 0x41;*

  • my_buff[56] = 0x54;*

  • my_buff[57] = 0x31;*

  • my_buff[58] = 0x36;*

  • my_buff[59] = 0x20;*

  • my_buff[60] = 0x20;*

  • my_buff[61] = 0x20;*

  • my_buff[510] = 0x55;*

  • my_buff[511] = 0xAA;*

  • sd_raw_sync();*

  • sd_raw_write(BR_LOCATION, my_buff, 512);*

  • sd_raw_sync();*

  • return(0x55); //Successful format*
    }