Patch from David Gustafsson: break out SPI functions and fix bug in capacity

calculation.

Removed expensive modulo operations from sd_read and sd_write because the block size is now a variable. (nvt)
This commit is contained in:
nvt-se 2009-11-03 15:21:43 +00:00
parent 9b801b59c7
commit 9b4cd05e1f
4 changed files with 89 additions and 64 deletions

View File

@ -38,9 +38,10 @@
*/ */
#include "contiki.h" #include "contiki.h"
#include "msb430-uart1.h"
#include "sd-arch.h" #include "sd-arch.h"
#include <string.h> #define SPI_IDLE 0xff
int int
sd_arch_init(void) sd_arch_init(void)
@ -58,3 +59,32 @@ sd_arch_init(void)
return 0; return 0;
} }
void
sd_arch_spi_write(int c)
{
UART_TX = c;
UART_WAIT_TXDONE();
}
void
sd_arch_spi_write_block(uint8_t *bytes, int amount)
{
int i;
for(i = 0; i < amount; i++) {
UART_TX = bytes[i];
UART_WAIT_TXDONE();
UART_RX;
}
}
unsigned
sd_arch_spi_read(void)
{
UART_TX = SPI_IDLE;
UART_WAIT_RX();
return UART_RX;
}

View File

@ -73,5 +73,8 @@
#define SD_READ_BLOCK_ATTEMPTS 2 #define SD_READ_BLOCK_ATTEMPTS 2
int sd_arch_init(void); int sd_arch_init(void);
void sd_arch_spi_write(int c);
void sd_arch_spi_write_block(uint8_t *bytes, int amount);
unsigned sd_arch_spi_read(void);
#endif /* !SD_ARCH_H */ #endif /* !SD_ARCH_H */

View File

@ -38,8 +38,8 @@
*/ */
#include "contiki.h" #include "contiki.h"
#include "msb430-uart1.h"
#include "sd.h" #include "sd.h"
#include "sd-arch.h"
#include <string.h> #include <string.h>
@ -83,33 +83,10 @@
#define DATA_CRC_ERROR 5 #define DATA_CRC_ERROR 5
#define DATA_WRITE_ERROR 6 #define DATA_WRITE_ERROR 6
/*---------------------------------------------------------------------------*/ static uint16_t rw_block_size;
static void static uint16_t block_size;
spi_write(int c)
{
UART_TX = c;
UART_WAIT_TXDONE();
}
/*---------------------------------------------------------------------------*/
static unsigned
spi_read(void)
{
UART_TX = SPI_IDLE;
UART_WAIT_RX();
return UART_RX;
}
/*---------------------------------------------------------------------------*/
static void
spi_write_block(uint8_t *bytes, int amount)
{
int i;
for(i = 0; i < amount; i++) { static int read_register(int register_cmd, char *buf, int register_size);
UART_TX = bytes[i];
UART_WAIT_TXDONE();
UART_RX;
}
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
send_command(uint8_t cmd, uint32_t argument) send_command(uint8_t cmd, uint32_t argument)
@ -125,9 +102,9 @@ send_command(uint8_t cmd, uint32_t argument)
GO_IDLE_STATE command. */ GO_IDLE_STATE command. */
req[5] = 0x95; req[5] = 0x95;
spi_write(SPI_IDLE); sd_arch_spi_write(SPI_IDLE);
spi_write_block(req, sizeof(req)); sd_arch_spi_write_block(req, sizeof(req));
spi_write(SPI_IDLE); sd_arch_spi_write(SPI_IDLE);
return 0; return 0;
} }
@ -140,7 +117,7 @@ get_response(int length)
static uint8_t r[R7]; static uint8_t r[R7];
for(i = 0; i < SD_READ_RESPONSE_ATTEMPTS; i++) { for(i = 0; i < SD_READ_RESPONSE_ATTEMPTS; i++) {
x = spi_read(); x = sd_arch_spi_read();
if((x & 0x80) == 0) { if((x & 0x80) == 0) {
/* A get_response byte is indicated by the MSB being 0. */ /* A get_response byte is indicated by the MSB being 0. */
r[0] = x; r[0] = x;
@ -153,7 +130,7 @@ get_response(int length)
} }
for(i = 1; i < length; i++) { for(i = 1; i < length; i++) {
r[i] = spi_read(); r[i] = sd_arch_spi_read();
} }
return r; return r;
@ -185,8 +162,9 @@ transaction(int command, unsigned long argument,
int int
sd_initialize(void) sd_initialize(void)
{ {
unsigned char reg[16];
int i; int i;
uint8_t *r; uint8_t *r, read_bl_len;
if(sd_arch_init() < 0) { if(sd_arch_init() < 0) {
return SD_INIT_ERROR_ARCH; return SD_INIT_ERROR_ARCH;
@ -249,6 +227,17 @@ sd_initialize(void)
PRINTF("OCR: %d %d %d %d %d\n", r[0], r[1], r[2], r[3], r[4]); PRINTF("OCR: %d %d %d %d %d\n", r[0], r[1], r[2], r[3], r[4]);
} }
if(read_register(SEND_CSD, reg, sizeof(reg)) < 0) {
PRINTF("Failed to get block size of SD card\n");
return SD_INIT_ERROR_NO_BLOCK_SIZE;
}
read_bl_len = reg[5] & 0x0f;
block_size = 1 << read_bl_len;
rw_block_size = (block_size > 512) ? 512 : block_size;
PRINTF("Found block size %d\n", block_size);
/* XXX Arbitrary wait time here. Need to investigate why this is needed. */ /* XXX Arbitrary wait time here. Need to investigate why this is needed. */
MS_DELAY(5); MS_DELAY(5);
@ -280,20 +269,20 @@ sd_write_block(sd_offset_t offset, char *buf)
if(r != NULL && r[0] == 0) { if(r != NULL && r[0] == 0) {
/* We received an R1 response with no errors. /* We received an R1 response with no errors.
Send a start block token to the card now. */ Send a start block token to the card now. */
spi_write(START_BLOCK_TOKEN); sd_arch_spi_write(START_BLOCK_TOKEN);
/* Write the data block. */ /* Write the data block. */
spi_write_block(buf, SD_BLOCK_SIZE); sd_arch_spi_write_block(buf, rw_block_size);
/* Get a response from the card. */ /* Get a response from the card. */
retval = SD_WRITE_ERROR_NO_BLOCK_RESPONSE; retval = SD_WRITE_ERROR_NO_BLOCK_RESPONSE;
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) { for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
data_response = spi_read(); data_response = sd_arch_spi_read();
if((data_response & 0x11) == 1) { if((data_response & 0x11) == 1) {
/* Data response token received. */ /* Data response token received. */
status_code = (data_response >> 1) & 0x7; status_code = (data_response >> 1) & 0x7;
if(status_code == DATA_ACCEPTED) { if(status_code == DATA_ACCEPTED) {
retval = SD_BLOCK_SIZE; retval = rw_block_size;
} else { } else {
retval = SD_WRITE_ERROR_PROGRAMMING; retval = SD_WRITE_ERROR_PROGRAMMING;
} }
@ -333,7 +322,7 @@ read_block(unsigned read_cmd, sd_offset_t offset, char *buf, int len)
/* We received an R1 response with no errors. /* We received an R1 response with no errors.
Get a token from the card now. */ Get a token from the card now. */
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) { for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
token = spi_read(); token = sd_arch_spi_read();
if(token == START_BLOCK_TOKEN || (token > 0 && token <= 8)) { if(token == START_BLOCK_TOKEN || (token > 0 && token <= 8)) {
break; break;
} }
@ -342,14 +331,14 @@ read_block(unsigned read_cmd, sd_offset_t offset, char *buf, int len)
if(token == START_BLOCK_TOKEN) { if(token == START_BLOCK_TOKEN) {
/* A start block token has been received. Read the block now. */ /* A start block token has been received. Read the block now. */
for(i = 0; i < len; i++) { for(i = 0; i < len; i++) {
buf[i] = spi_read(); buf[i] = sd_arch_spi_read();
} }
/* Consume CRC. TODO: Validate the block. */ /* Consume CRC. TODO: Validate the block. */
spi_read(); sd_arch_spi_read();
spi_read(); sd_arch_spi_read();
retval = SD_BLOCK_SIZE; retval = len;
} else if(token > 0 && token <= 8) { } else if(token > 0 && token <= 8) {
/* The card returned a data error token. */ /* The card returned a data error token. */
retval = SD_READ_ERROR_TOKEN; retval = SD_READ_ERROR_TOKEN;
@ -376,7 +365,7 @@ read_block(unsigned read_cmd, sd_offset_t offset, char *buf, int len)
int int
sd_read_block(sd_offset_t offset, char *buf) sd_read_block(sd_offset_t offset, char *buf)
{ {
return read_block(READ_SINGLE_BLOCK, offset, buf, SD_BLOCK_SIZE); return read_block(READ_SINGLE_BLOCK, offset, buf, rw_block_size);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
@ -400,12 +389,12 @@ sd_get_capacity(void)
return r; return r;
} }
c_size = ((reg[6] & 3) << 10) + (reg[7] << 2) + (reg[8] & 3); c_size = ((reg[6] & 3) << 10) + (reg[7] << 2) + ((reg[8] >> 6) & 3);
c_size_mult = ((reg[9] & 3) << 1) + ((reg[10] & 0x80) >> 7); c_size_mult = ((reg[9] & 3) << 1) + ((reg[10] & 0x80) >> 7);
mult = 2 << (c_size_mult + 2); mult = 1 << (c_size_mult + 2);
block_nr = (c_size + 1) * mult; block_nr = (c_size + 1) * mult;
return block_nr * SD_BLOCK_SIZE; return block_nr * block_size;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
char * char *
@ -421,6 +410,8 @@ sd_error_string(int error_code)
return "architecture-dependent initialization failed"; return "architecture-dependent initialization failed";
case SD_INIT_ERROR_NO_IF_COND: case SD_INIT_ERROR_NO_IF_COND:
return "unable to obtain the interface condition"; return "unable to obtain the interface condition";
case SD_INIT_ERROR_NO_BLOCK_SIZE:
return "unable to obtain the block size";
case SD_WRITE_ERROR_NO_CMD_RESPONSE: case SD_WRITE_ERROR_NO_CMD_RESPONSE:
return "no response from the card after submitting a write request"; return "no response from the card after submitting a write request";
case SD_WRITE_ERROR_NO_BLOCK_RESPONSE: case SD_WRITE_ERROR_NO_BLOCK_RESPONSE:
@ -453,16 +444,16 @@ sd_write(sd_offset_t offset, char *buf, size_t size)
int r, i; int r, i;
size_t written; size_t written;
size_t to_write; size_t to_write;
char sd_buf[SD_BLOCK_SIZE]; char sd_buf[rw_block_size];
/* Emulation of data writing using arbitrary offsets and chunk sizes. */ /* Emulation of data writing using arbitrary offsets and chunk sizes. */
memset(sd_buf, 0, sizeof(sd_buf)); memset(sd_buf, 0, sizeof(sd_buf));
written = 0; written = 0;
offset_in_block = offset % SD_BLOCK_SIZE; offset_in_block = offset & (rw_block_size - 1);
do { do {
to_write = MIN(size - written, SD_BLOCK_SIZE - offset_in_block); to_write = MIN(size - written, rw_block_size - offset_in_block);
address = (offset + written) & ~(SD_BLOCK_SIZE - 1); address = (offset + written) & ~(rw_block_size - 1);
for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) { for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) {
r = sd_read_block(address, sd_buf); r = sd_read_block(address, sd_buf);
@ -491,18 +482,18 @@ sd_read(sd_offset_t offset, char *buf, size_t size)
{ {
size_t total_read; size_t total_read;
size_t to_read; size_t to_read;
char sd_buf[SD_BLOCK_SIZE]; char sd_buf[rw_block_size];
uint16_t offset_in_block; uint16_t offset_in_block;
int r, i; int r, i;
/* Emulation of data reading using arbitrary offsets and chunk sizes. */ /* Emulation of data reading using arbitrary offsets and chunk sizes. */
total_read = 0; total_read = 0;
offset_in_block = offset % SD_BLOCK_SIZE; offset_in_block = offset & (rw_block_size - 1);
do { do {
to_read = MIN(size - total_read, SD_BLOCK_SIZE - offset_in_block); to_read = MIN(size - total_read, rw_block_size - offset_in_block);
for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) { for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) {
r = sd_read_block((offset + total_read) & ~(SD_BLOCK_SIZE - 1), sd_buf); r = sd_read_block((offset + total_read) & ~(rw_block_size - 1), sd_buf);
if(r == sizeof(sd_buf)) { if(r == sizeof(sd_buf)) {
break; break;
} }

View File

@ -51,17 +51,18 @@
#define SD_INIT_ERROR_NO_CARD -1 #define SD_INIT_ERROR_NO_CARD -1
#define SD_INIT_ERROR_ARCH -2 #define SD_INIT_ERROR_ARCH -2
#define SD_INIT_ERROR_NO_IF_COND -3 #define SD_INIT_ERROR_NO_IF_COND -3
#define SD_INIT_ERROR_NO_BLOCK_SIZE -4
#define SD_WRITE_ERROR_NO_CMD_RESPONSE -4 #define SD_WRITE_ERROR_NO_CMD_RESPONSE -5
#define SD_WRITE_ERROR_NO_BLOCK_RESPONSE -5 #define SD_WRITE_ERROR_NO_BLOCK_RESPONSE -6
#define SD_WRITE_ERROR_PROGRAMMING -6 #define SD_WRITE_ERROR_PROGRAMMING -7
#define SD_WRITE_ERROR_TOKEN -7 #define SD_WRITE_ERROR_TOKEN -8
#define SD_WRITE_ERROR_NO_TOKEN -8 #define SD_WRITE_ERROR_NO_TOKEN -9
#define SD_READ_ERROR_NO_CMD_RESPONSE -9 #define SD_READ_ERROR_NO_CMD_RESPONSE -10
#define SD_READ_ERROR_INVALID_SIZE -10 #define SD_READ_ERROR_INVALID_SIZE -11
#define SD_READ_ERROR_TOKEN -11 #define SD_READ_ERROR_TOKEN -12
#define SD_READ_ERROR_NO_TOKEN -12 #define SD_READ_ERROR_NO_TOKEN -13
/* Type definition. */ /* Type definition. */
typedef uint32_t sd_offset_t; typedef uint32_t sd_offset_t;