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*
}