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:
parent
9b801b59c7
commit
9b4cd05e1f
4 changed files with 89 additions and 64 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue