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 "msb430-uart1.h"
#include "sd-arch.h"
#include <string.h>
#define SPI_IDLE 0xff
int
sd_arch_init(void)
@ -58,3 +59,32 @@ sd_arch_init(void)
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
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 */

View file

@ -38,8 +38,8 @@
*/
#include "contiki.h"
#include "msb430-uart1.h"
#include "sd.h"
#include "sd-arch.h"
#include <string.h>
@ -83,33 +83,10 @@
#define DATA_CRC_ERROR 5
#define DATA_WRITE_ERROR 6
/*---------------------------------------------------------------------------*/
static void
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;
static uint16_t rw_block_size;
static uint16_t block_size;
for(i = 0; i < amount; i++) {
UART_TX = bytes[i];
UART_WAIT_TXDONE();
UART_RX;
}
}
static int read_register(int register_cmd, char *buf, int register_size);
/*---------------------------------------------------------------------------*/
static int
send_command(uint8_t cmd, uint32_t argument)
@ -125,9 +102,9 @@ send_command(uint8_t cmd, uint32_t argument)
GO_IDLE_STATE command. */
req[5] = 0x95;
spi_write(SPI_IDLE);
spi_write_block(req, sizeof(req));
spi_write(SPI_IDLE);
sd_arch_spi_write(SPI_IDLE);
sd_arch_spi_write_block(req, sizeof(req));
sd_arch_spi_write(SPI_IDLE);
return 0;
}
@ -140,7 +117,7 @@ get_response(int length)
static uint8_t r[R7];
for(i = 0; i < SD_READ_RESPONSE_ATTEMPTS; i++) {
x = spi_read();
x = sd_arch_spi_read();
if((x & 0x80) == 0) {
/* A get_response byte is indicated by the MSB being 0. */
r[0] = x;
@ -153,7 +130,7 @@ get_response(int length)
}
for(i = 1; i < length; i++) {
r[i] = spi_read();
r[i] = sd_arch_spi_read();
}
return r;
@ -185,8 +162,9 @@ transaction(int command, unsigned long argument,
int
sd_initialize(void)
{
unsigned char reg[16];
int i;
uint8_t *r;
uint8_t *r, read_bl_len;
if(sd_arch_init() < 0) {
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]);
}
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. */
MS_DELAY(5);
@ -280,20 +269,20 @@ sd_write_block(sd_offset_t offset, char *buf)
if(r != NULL && r[0] == 0) {
/* We received an R1 response with no errors.
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. */
spi_write_block(buf, SD_BLOCK_SIZE);
sd_arch_spi_write_block(buf, rw_block_size);
/* Get a response from the card. */
retval = SD_WRITE_ERROR_NO_BLOCK_RESPONSE;
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
data_response = spi_read();
data_response = sd_arch_spi_read();
if((data_response & 0x11) == 1) {
/* Data response token received. */
status_code = (data_response >> 1) & 0x7;
if(status_code == DATA_ACCEPTED) {
retval = SD_BLOCK_SIZE;
retval = rw_block_size;
} else {
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.
Get a token from the card now. */
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)) {
break;
}
@ -342,14 +331,14 @@ read_block(unsigned read_cmd, sd_offset_t offset, char *buf, int len)
if(token == START_BLOCK_TOKEN) {
/* A start block token has been received. Read the block now. */
for(i = 0; i < len; i++) {
buf[i] = spi_read();
buf[i] = sd_arch_spi_read();
}
/* Consume CRC. TODO: Validate the block. */
spi_read();
spi_read();
sd_arch_spi_read();
sd_arch_spi_read();
retval = SD_BLOCK_SIZE;
retval = len;
} else if(token > 0 && token <= 8) {
/* The card returned a data 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
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
@ -400,12 +389,12 @@ sd_get_capacity(void)
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);
mult = 2 << (c_size_mult + 2);
mult = 1 << (c_size_mult + 2);
block_nr = (c_size + 1) * mult;
return block_nr * SD_BLOCK_SIZE;
return block_nr * block_size;
}
/*---------------------------------------------------------------------------*/
char *
@ -421,6 +410,8 @@ sd_error_string(int error_code)
return "architecture-dependent initialization failed";
case SD_INIT_ERROR_NO_IF_COND:
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:
return "no response from the card after submitting a write request";
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;
size_t written;
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. */
memset(sd_buf, 0, sizeof(sd_buf));
written = 0;
offset_in_block = offset % SD_BLOCK_SIZE;
offset_in_block = offset & (rw_block_size - 1);
do {
to_write = MIN(size - written, SD_BLOCK_SIZE - offset_in_block);
address = (offset + written) & ~(SD_BLOCK_SIZE - 1);
to_write = MIN(size - written, rw_block_size - offset_in_block);
address = (offset + written) & ~(rw_block_size - 1);
for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) {
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 to_read;
char sd_buf[SD_BLOCK_SIZE];
char sd_buf[rw_block_size];
uint16_t offset_in_block;
int r, i;
/* Emulation of data reading using arbitrary offsets and chunk sizes. */
total_read = 0;
offset_in_block = offset % SD_BLOCK_SIZE;
offset_in_block = offset & (rw_block_size - 1);
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++) {
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)) {
break;
}

View file

@ -51,17 +51,18 @@
#define SD_INIT_ERROR_NO_CARD -1
#define SD_INIT_ERROR_ARCH -2
#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_BLOCK_RESPONSE -5
#define SD_WRITE_ERROR_PROGRAMMING -6
#define SD_WRITE_ERROR_TOKEN -7
#define SD_WRITE_ERROR_NO_TOKEN -8
#define SD_WRITE_ERROR_NO_CMD_RESPONSE -5
#define SD_WRITE_ERROR_NO_BLOCK_RESPONSE -6
#define SD_WRITE_ERROR_PROGRAMMING -7
#define SD_WRITE_ERROR_TOKEN -8
#define SD_WRITE_ERROR_NO_TOKEN -9
#define SD_READ_ERROR_NO_CMD_RESPONSE -9
#define SD_READ_ERROR_INVALID_SIZE -10
#define SD_READ_ERROR_TOKEN -11
#define SD_READ_ERROR_NO_TOKEN -12
#define SD_READ_ERROR_NO_CMD_RESPONSE -10
#define SD_READ_ERROR_INVALID_SIZE -11
#define SD_READ_ERROR_TOKEN -12
#define SD_READ_ERROR_NO_TOKEN -13
/* Type definition. */
typedef uint32_t sd_offset_t;