added a simple driver for using SD devices through the SPI.
This commit is contained in:
parent
a71cd04144
commit
ea56edc5c2
|
@ -2,7 +2,8 @@ SENSORS = sensors.c irq.c sht11.c
|
||||||
MSB = dma.c infomem.c node-id.c \
|
MSB = dma.c infomem.c node-id.c \
|
||||||
msb430-uart1.c rs232.c \
|
msb430-uart1.c rs232.c \
|
||||||
cc1020.c cc1020-uip.c adc.c init-net-rime.c \
|
cc1020.c cc1020-uip.c adc.c init-net-rime.c \
|
||||||
msb430-slip-arch.c
|
msb430-slip-arch.c sd.c sd-arch.c \
|
||||||
|
cfs-coffee.c cfs-coffee-arch.c
|
||||||
|
|
||||||
CONTIKI_TARGET_DIRS = . dev apps loader
|
CONTIKI_TARGET_DIRS = . dev apps loader
|
||||||
ifndef CONTIKI_TARGET_MAIN
|
ifndef CONTIKI_TARGET_MAIN
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
#include "contiki-msb430.h"
|
#include "contiki-msb430.h"
|
||||||
#include "dev/adc.h"
|
#include "dev/adc.h"
|
||||||
|
#include "dev/sd.h"
|
||||||
#include "dev/serial-line.h"
|
#include "dev/serial-line.h"
|
||||||
#include "dev/sht11.h"
|
#include "dev/sht11.h"
|
||||||
#include "dev/watchdog.h"
|
#include "dev/watchdog.h"
|
||||||
|
@ -82,11 +83,10 @@ main(void)
|
||||||
leds_init();
|
leds_init();
|
||||||
leds_on(LEDS_ALL);
|
leds_on(LEDS_ALL);
|
||||||
|
|
||||||
// low level
|
|
||||||
irq_init();
|
irq_init();
|
||||||
process_init();
|
process_init();
|
||||||
|
|
||||||
// serial interface
|
/* serial interface */
|
||||||
rs232_set_input(serial_line_input_byte);
|
rs232_set_input(serial_line_input_byte);
|
||||||
rs232_init();
|
rs232_init();
|
||||||
serial_line_init();
|
serial_line_init();
|
||||||
|
@ -97,6 +97,23 @@ main(void)
|
||||||
slip_arch_init(BAUD2UBR(115200));
|
slip_arch_init(BAUD2UBR(115200));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if WITH_SD
|
||||||
|
r = sd_initialize();
|
||||||
|
if(r < 0) {
|
||||||
|
printf("Failed to initialize the SD driver: %s\n", sd_error_string(r));
|
||||||
|
} else {
|
||||||
|
sd_offset_t capacity;
|
||||||
|
printf("The SD driver was successfully initialized\n");
|
||||||
|
capacity = sd_get_capacity();
|
||||||
|
if(capacity < 0) {
|
||||||
|
printf("Failed to get the card capacity: %s\n", sd_error_string(r));
|
||||||
|
} else {
|
||||||
|
printf("Card capacity: %lu\n", (unsigned long)capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* System services */
|
/* System services */
|
||||||
process_start(&etimer_process, NULL);
|
process_start(&etimer_process, NULL);
|
||||||
ctimer_init();
|
ctimer_init();
|
||||||
|
|
|
@ -47,8 +47,13 @@
|
||||||
#include "dev/rs232.h"
|
#include "dev/rs232.h"
|
||||||
#include "dev/serial-line.h"
|
#include "dev/serial-line.h"
|
||||||
#include "dev/slip.h"
|
#include "dev/slip.h"
|
||||||
|
|
||||||
#include "lib/sensors.h"
|
#include "lib/sensors.h"
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
#include "node-id.h"
|
#include "node-id.h"
|
||||||
|
|
||||||
|
#if WITH_SD
|
||||||
|
#include "dev/sd.h"
|
||||||
|
#endif /* WITH_SD */
|
||||||
|
|
||||||
#endif /* !CONTIKI_MSB430_H */
|
#endif /* !CONTIKI_MSB430_H */
|
||||||
|
|
60
platform/msb430/dev/sd-arch.c
Executable file
60
platform/msb430/dev/sd-arch.c
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Swedish Institute of Computer Science
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Architecture-dependent functions for SD over SPI.
|
||||||
|
* \author
|
||||||
|
* Nicolas Tsiftes <nvt@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "sd-arch.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
sd_arch_init(void)
|
||||||
|
{
|
||||||
|
P2SEL &= ~64;
|
||||||
|
P2DIR &= ~64;
|
||||||
|
|
||||||
|
P5SEL |= 14;
|
||||||
|
P5SEL &= ~1;
|
||||||
|
P5OUT |= 1;
|
||||||
|
P5DIR |= 13;
|
||||||
|
P5DIR &= ~2;
|
||||||
|
|
||||||
|
uart_set_speed(UART_MODE_SPI, 2, 0, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
73
platform/msb430/dev/sd-arch.h
Executable file
73
platform/msb430/dev/sd-arch.h
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Swedish Institute of Computer Science
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* SD driver implementation using SPI.
|
||||||
|
* \author
|
||||||
|
* Nicolas Tsiftes <nvt@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SD_ARCH_H
|
||||||
|
#define SD_ARCH_H
|
||||||
|
|
||||||
|
#include "msb430-uart1.h"
|
||||||
|
|
||||||
|
#define MS_DELAY(x) clock_delay(354 * (x))
|
||||||
|
|
||||||
|
/* Machine-dependent macros. */
|
||||||
|
#define LOCK_SPI() do { \
|
||||||
|
if(!uart_lock(UART_MODE_SPI)) {\
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#define UNLOCK_SPI() do { \
|
||||||
|
uart_unlock(UART_MODE_SPI); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SD_CONNECTED() !(P2IN & 0x40)
|
||||||
|
#define LOWER_CS() (P5OUT &= ~0x01)
|
||||||
|
#define RAISE_CS() do { \
|
||||||
|
UART_WAIT_TXDONE(); \
|
||||||
|
P5OUT |= 0x01; \
|
||||||
|
UART_TX = SPI_IDLE; \
|
||||||
|
UART_WAIT_TXDONE(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/* Configuration parameters. */
|
||||||
|
#define SD_TRANSACTION_ATTEMPTS 512
|
||||||
|
#define SD_READ_RESPONSE_ATTEMPTS 8
|
||||||
|
#define SD_READ_BLOCK_ATTEMPTS 2
|
||||||
|
|
||||||
|
int sd_arch_init(void);
|
||||||
|
|
||||||
|
#endif /* !SD_ARCH_H */
|
527
platform/msb430/dev/sd.c
Executable file
527
platform/msb430/dev/sd.c
Executable file
|
@ -0,0 +1,527 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Swedish Institute of Computer Science
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* SD driver implementation using SPI.
|
||||||
|
* \author
|
||||||
|
* Nicolas Tsiftes <nvt@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "msb430-uart1.h"
|
||||||
|
#include "sd.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
#if DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#define PRINTF(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define PRINTF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif /* MIN */
|
||||||
|
|
||||||
|
#define SPI_IDLE 0xff
|
||||||
|
|
||||||
|
/* SD commands */
|
||||||
|
#define GO_IDLE_STATE 0
|
||||||
|
#define SEND_OP_COND 1
|
||||||
|
#define SWITCH_FUNC 6
|
||||||
|
#define SEND_IF_COND 8
|
||||||
|
#define SEND_CSD 9
|
||||||
|
#define SEND_CID 10
|
||||||
|
#define STOP_TRANSMISSION 12
|
||||||
|
#define SEND_STATUS 13
|
||||||
|
#define READ_SINGLE_BLOCK 17
|
||||||
|
#define WRITE_BLOCK 24
|
||||||
|
#define READ_OCR 58
|
||||||
|
|
||||||
|
/* SD response lengths. */
|
||||||
|
#define R1 1
|
||||||
|
#define R2 2
|
||||||
|
#define R3 5
|
||||||
|
#define R7 5
|
||||||
|
|
||||||
|
#define START_BLOCK_TOKEN 0xfe
|
||||||
|
|
||||||
|
/* Status codes returned after writing a block. */
|
||||||
|
#define DATA_ACCEPTED 2
|
||||||
|
#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;
|
||||||
|
|
||||||
|
for(i = 0; i < amount; i++) {
|
||||||
|
UART_TX = bytes[i];
|
||||||
|
UART_WAIT_TXDONE();
|
||||||
|
UART_RX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
send_command(uint8_t cmd, uint32_t argument)
|
||||||
|
{
|
||||||
|
uint8_t req[6];
|
||||||
|
|
||||||
|
req[0] = 0x40 | cmd;
|
||||||
|
req[1] = argument >> 24;
|
||||||
|
req[2] = argument >> 16;
|
||||||
|
req[3] = argument >> 8;
|
||||||
|
req[4] = argument;
|
||||||
|
/* The CRC hard-wired to 0x95 is only needed for the initial
|
||||||
|
GO_IDLE_STATE command. */
|
||||||
|
req[5] = 0x95;
|
||||||
|
|
||||||
|
spi_write(SPI_IDLE);
|
||||||
|
spi_write_block(req, sizeof(req));
|
||||||
|
spi_write(SPI_IDLE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static uint8_t *
|
||||||
|
get_response(int length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int x;
|
||||||
|
static uint8_t r[R7];
|
||||||
|
|
||||||
|
for(i = 0; i < SD_READ_RESPONSE_ATTEMPTS; i++) {
|
||||||
|
x = spi_read();
|
||||||
|
if((x & 0x80) == 0) {
|
||||||
|
/* A get_response byte is indicated by the MSB being 0. */
|
||||||
|
r[0] = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == SD_READ_RESPONSE_ATTEMPTS) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 1; i < length; i++) {
|
||||||
|
r[i] = spi_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static unsigned char *
|
||||||
|
transaction(int command, unsigned long argument,
|
||||||
|
int response_type, unsigned attempts)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned char *r;
|
||||||
|
|
||||||
|
LOCK_SPI();
|
||||||
|
r = NULL;
|
||||||
|
for(i = 0; i < attempts; i++) {
|
||||||
|
LOWER_CS();
|
||||||
|
send_command(command, argument);
|
||||||
|
r = get_response(response_type);
|
||||||
|
RAISE_CS();
|
||||||
|
if(r != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNLOCK_SPI();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
sd_initialize(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *r;
|
||||||
|
|
||||||
|
if(sd_arch_init() < 0) {
|
||||||
|
return SD_INIT_ERROR_ARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SD_CONNECTED() < 0) {
|
||||||
|
return SD_INIT_ERROR_NO_CARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = transaction(GO_IDLE_STATE, 0, R1, SD_TRANSACTION_ATTEMPTS);
|
||||||
|
if(r != NULL) {
|
||||||
|
PRINTF("Go-idle result: %d\n", r[0]);
|
||||||
|
} else {
|
||||||
|
PRINTF("Failed to get go-idle response\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
r = transaction(SEND_IF_COND, 0, R7, SD_TRANSACTION_ATTEMPTS);
|
||||||
|
if(r != NULL) {
|
||||||
|
PRINTF("IF cond: %d %d %d %d %d\n", r[0], r[1], r[2], r[3], r[4]);
|
||||||
|
} else {
|
||||||
|
PRINTF("failed to get IF cond\n");
|
||||||
|
return SD_INIT_ERROR_NO_IF_COND;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_SPI();
|
||||||
|
|
||||||
|
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
|
||||||
|
LOWER_CS();
|
||||||
|
send_command(SEND_OP_COND, 0);
|
||||||
|
r = get_response(R1);
|
||||||
|
RAISE_CS();
|
||||||
|
if(r != NULL && !(r[0] & 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_SPI();
|
||||||
|
|
||||||
|
if(r != NULL) {
|
||||||
|
PRINTF("OP cond: %d (%d iterations)\n", r[0], i);
|
||||||
|
} else {
|
||||||
|
PRINTF("Failed to get OP cond get_response\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_SPI();
|
||||||
|
|
||||||
|
for(i = 0; i < 10000; i++) {
|
||||||
|
LOWER_CS();
|
||||||
|
send_command(READ_OCR, 0);
|
||||||
|
r = get_response(R3);
|
||||||
|
RAISE_CS();
|
||||||
|
if(r != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_SPI();
|
||||||
|
|
||||||
|
if(r != NULL) {
|
||||||
|
PRINTF("OCR: %d %d %d %d %d\n", r[0], r[1], r[2], r[3], r[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX Arbitrary wait time here. Need to investigate why this is needed. */
|
||||||
|
MS_DELAY(5);
|
||||||
|
|
||||||
|
return SD_OK;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
sd_write_block(sd_offset_t offset, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char *r;
|
||||||
|
int retval;
|
||||||
|
int i;
|
||||||
|
unsigned char data_response;
|
||||||
|
unsigned char status_code;
|
||||||
|
|
||||||
|
LOCK_SPI();
|
||||||
|
r = NULL;
|
||||||
|
retval = SD_WRITE_ERROR_NO_CMD_RESPONSE;
|
||||||
|
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
|
||||||
|
LOWER_CS();
|
||||||
|
send_command(WRITE_BLOCK, offset);
|
||||||
|
r = get_response(R1);
|
||||||
|
if(r != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RAISE_CS();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Write the data block. */
|
||||||
|
spi_write_block(buf, SD_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();
|
||||||
|
if((data_response & 0x11) == 1) {
|
||||||
|
/* Data response token received. */
|
||||||
|
status_code = (data_response >> 1) & 0x7;
|
||||||
|
if(status_code == DATA_ACCEPTED) {
|
||||||
|
retval = SD_BLOCK_SIZE;
|
||||||
|
} else {
|
||||||
|
retval = SD_WRITE_ERROR_PROGRAMMING;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RAISE_CS();
|
||||||
|
UNLOCK_SPI();
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
read_block(unsigned read_cmd, sd_offset_t offset, char *buf, int len)
|
||||||
|
{
|
||||||
|
unsigned char *r;
|
||||||
|
int i;
|
||||||
|
int token;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
LOCK_SPI();
|
||||||
|
|
||||||
|
r = NULL;
|
||||||
|
for(i = 0; i < SD_TRANSACTION_ATTEMPTS; i++) {
|
||||||
|
LOWER_CS();
|
||||||
|
send_command(read_cmd, offset);
|
||||||
|
r = get_response(R1);
|
||||||
|
if(r != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RAISE_CS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r != NULL && r[0] == 0) {
|
||||||
|
/* 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();
|
||||||
|
if(token == START_BLOCK_TOKEN || (token > 0 && token <= 8)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume CRC. TODO: Validate the block. */
|
||||||
|
spi_read();
|
||||||
|
spi_read();
|
||||||
|
|
||||||
|
retval = SD_BLOCK_SIZE;
|
||||||
|
} else if(token > 0 && token <= 8) {
|
||||||
|
/* The card returned a data error token. */
|
||||||
|
retval = SD_READ_ERROR_TOKEN;
|
||||||
|
} else {
|
||||||
|
/* The card never returned a token after our read attempts. */
|
||||||
|
retval = SD_READ_ERROR_NO_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAISE_CS();
|
||||||
|
UNLOCK_SPI();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAISE_CS();
|
||||||
|
UNLOCK_SPI();
|
||||||
|
|
||||||
|
if(r != NULL) {
|
||||||
|
PRINTF("status during read: %d\n", r[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SD_READ_ERROR_NO_CMD_RESPONSE;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
sd_read_block(sd_offset_t offset, char *buf)
|
||||||
|
{
|
||||||
|
return read_block(READ_SINGLE_BLOCK, offset, buf, SD_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
read_register(int register_cmd, char *buf, int register_size)
|
||||||
|
{
|
||||||
|
return read_block(register_cmd, 0, buf, register_size);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
unsigned
|
||||||
|
sd_get_block_size(void)
|
||||||
|
{
|
||||||
|
return SD_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
sd_offset_t
|
||||||
|
sd_get_capacity(void)
|
||||||
|
{
|
||||||
|
unsigned char reg[16];
|
||||||
|
int r;
|
||||||
|
uint16_t c_size;
|
||||||
|
uint8_t c_size_mult;
|
||||||
|
sd_offset_t block_nr;
|
||||||
|
sd_offset_t mult;
|
||||||
|
|
||||||
|
r = read_register(SEND_CSD, reg, sizeof(reg));
|
||||||
|
if(r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_size = ((reg[6] & 3) << 10) + (reg[7] << 2) + (reg[8] & 3);
|
||||||
|
c_size_mult = ((reg[9] & 3) << 1) + ((reg[10] & 0x80) >> 7);
|
||||||
|
mult = 2 << (c_size_mult + 2);
|
||||||
|
block_nr = (c_size + 1) * mult;
|
||||||
|
|
||||||
|
return block_nr * SD_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
char *
|
||||||
|
sd_error_string(int error_code)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
switch(error_code) {
|
||||||
|
case SD_OK:
|
||||||
|
return "operation succeeded";
|
||||||
|
case SD_INIT_ERROR_NO_CARD:
|
||||||
|
return "no card was found";
|
||||||
|
case SD_INIT_ERROR_ARCH:
|
||||||
|
return "architecture-dependent initialization failed";
|
||||||
|
case SD_INIT_ERROR_NO_IF_COND:
|
||||||
|
return "unable to obtain the interface condition";
|
||||||
|
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:
|
||||||
|
return "no response from the card after sending a data block";
|
||||||
|
case SD_WRITE_ERROR_PROGRAMMING:
|
||||||
|
return "the write request failed because of a card error";
|
||||||
|
case SD_WRITE_ERROR_TOKEN:
|
||||||
|
return "the card is not ready to grant a write request";
|
||||||
|
case SD_READ_ERROR_NO_TOKEN:
|
||||||
|
case SD_WRITE_ERROR_NO_TOKEN:
|
||||||
|
return "did not receive a start block token";
|
||||||
|
case SD_READ_ERROR_INVALID_SIZE:
|
||||||
|
return "invalid read block size";
|
||||||
|
case SD_READ_ERROR_TOKEN:
|
||||||
|
return "the card is not ready to read a data block";
|
||||||
|
case SD_READ_ERROR_NO_CMD_RESPONSE:
|
||||||
|
return "no response from the card after submitting a read request";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return "unspecified error";
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
sd_write(sd_offset_t offset, char *buf, size_t size)
|
||||||
|
{
|
||||||
|
sd_offset_t address;
|
||||||
|
uint16_t offset_in_block;
|
||||||
|
int r, i;
|
||||||
|
size_t written;
|
||||||
|
size_t to_write;
|
||||||
|
char sd_buf[SD_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;
|
||||||
|
|
||||||
|
do {
|
||||||
|
to_write = MIN(size - written, SD_BLOCK_SIZE - offset_in_block);
|
||||||
|
address = (offset + written) & ~(SD_BLOCK_SIZE - 1);
|
||||||
|
|
||||||
|
for(i = 0; i < SD_READ_BLOCK_ATTEMPTS; i++) {
|
||||||
|
r = sd_read_block(address, sd_buf);
|
||||||
|
if(r == sizeof(buf)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r != sizeof(sd_buf)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&sd_buf[offset_in_block], &buf[written], to_write);
|
||||||
|
r = sd_write_block(address, sd_buf);
|
||||||
|
if(r != sizeof(sd_buf)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
written += to_write;
|
||||||
|
offset_in_block = 0;
|
||||||
|
} while(written < size);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
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];
|
||||||
|
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;
|
||||||
|
|
||||||
|
do {
|
||||||
|
to_read = MIN(size - total_read, SD_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);
|
||||||
|
if(r == sizeof(sd_buf)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r != sizeof(sd_buf)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&buf[total_read], &sd_buf[offset_in_block], to_read);
|
||||||
|
total_read += to_read;
|
||||||
|
offset_in_block = 0;
|
||||||
|
} while(total_read < size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
79
platform/msb430/dev/sd.h
Normal file
79
platform/msb430/dev/sd.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Swedish Institute of Computer Science
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* SD driver interface.
|
||||||
|
* \author
|
||||||
|
* Nicolas Tsiftes <nvt@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SD_H
|
||||||
|
#define SD_H
|
||||||
|
|
||||||
|
#include "sd-arch.h"
|
||||||
|
|
||||||
|
#define SD_BLOCK_SIZE 512
|
||||||
|
#define SD_REGISTER_SIZE 16
|
||||||
|
|
||||||
|
/* API return codes. */
|
||||||
|
#define SD_OK 1
|
||||||
|
|
||||||
|
#define SD_INIT_ERROR_NO_CARD -1
|
||||||
|
#define SD_INIT_ERROR_ARCH -2
|
||||||
|
#define SD_INIT_ERROR_NO_IF_COND -3
|
||||||
|
|
||||||
|
#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_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
|
||||||
|
|
||||||
|
/* Type definition. */
|
||||||
|
typedef uint32_t sd_offset_t;
|
||||||
|
|
||||||
|
/* API */
|
||||||
|
int sd_initialize(void);
|
||||||
|
int sd_write(sd_offset_t, char *, unsigned);
|
||||||
|
int sd_read(sd_offset_t, char *, unsigned);
|
||||||
|
int sd_write_block(sd_offset_t, char *);
|
||||||
|
int sd_read_block(sd_offset_t, char *);
|
||||||
|
unsigned sd_get_block_size(void);
|
||||||
|
sd_offset_t sd_get_capacity(void);
|
||||||
|
char *sd_error_string(int);
|
||||||
|
|
||||||
|
#endif /* !SD_H */
|
Loading…
Reference in a new issue