diff --git a/platform/msb430/Makefile.msb430 b/platform/msb430/Makefile.msb430 index ca077036c..dcd38caa8 100644 --- a/platform/msb430/Makefile.msb430 +++ b/platform/msb430/Makefile.msb430 @@ -1,15 +1,16 @@ SENSORS = sensors.c irq.c sht11.c -#SD = sd.c sd_cache.c sd_erase.c sd_info.c +SD = sd.c sd_cache.c sd_erase.c sd_info.c MSB = dma.c infomem.c node-id.c \ - msb430-uart1.c rs232.c msb430-slip-arch.c \ - cc1020.c cc1020-uip.c adc.c init-net-rime.c + msb430-uart1.c rs232.c \ + cc1020.c cc1020-uip.c adc.c init-net-rime.c \ + msb430-slip-arch.c sdspi.c CONTIKI_TARGET_DIRS = . dev dev/sd apps net loader ifndef CONTIKI_TARGET_MAIN CONTIKI_TARGET_MAIN = contiki-msb430-main.c endif -CONTIKI_TARGET_SOURCEFILES += $(SENSORS) $(MSB) $(CONTIKI_TARGET_MAIN) +CONTIKI_TARGET_SOURCEFILES += $(SENSORS) $(SD) $(MSB) $(CONTIKI_TARGET_MAIN) include $(CONTIKI)/platform/$(TARGET)/apps/Makefile.apps diff --git a/platform/msb430/contiki-msb430-main.c b/platform/msb430/contiki-msb430-main.c index e8d2b3bbb..6bfc495a5 100644 --- a/platform/msb430/contiki-msb430-main.c +++ b/platform/msb430/contiki-msb430-main.c @@ -64,7 +64,12 @@ msb_ports_init(void) int main(void) { +#ifdef WITH_SDC + sd_cache_t sd_cache; +#endif + msp430_cpu_init(); + watchdog_stop(); /* Platform-specific initialization. */ msb_ports_init(); @@ -85,10 +90,6 @@ main(void) // serial interface rs232_init(); -#ifdef WITH_SDC - spi_init(); -#endif - uart_lock(UART_MODE_RS232); uart_unlock(UART_MODE_RS232); #if WITH_UIP @@ -110,6 +111,14 @@ main(void) leds_off(LEDS_ALL); +#ifdef WITH_SDC + spi_init(); + sd_init(); + if (sd_init_card(&sd_cache) == SD_INIT_SUCCESS) { + printf("SD card initialized\n"); + } +#endif + printf(CONTIKI_VERSION_STRING " started. Node id %u.\n", node_id); autostart_start(autostart_processes); diff --git a/platform/msb430/dev/sd/sd.c b/platform/msb430/dev/sd/sd.c new file mode 100644 index 000000000..a24ed6b0d --- /dev/null +++ b/platform/msb430/dev/sd/sd.c @@ -0,0 +1,649 @@ + +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.c + * @ingroup libsd + * @brief MMC-/SD-Card library + * + * @author Michael Baar + * @date Jan 2007 + * @version 0.2 + * + * Initialisation and basic functions for read and write access + */ + +#include "contiki-msb430.h" +#include "sd_internals.h" +#include "sd.h" + +volatile sd_state_t sd_state; + +/****************************************************************************** + * @name Initialization and configuration + * @{ + */ +void +sd_init() +{ + spi_init(); + P5SEL |= 0x0E; // 00 00 11 10 -> Dout, Din, Clk = peripheral (now done in UART module) + P5SEL &= ~0x01; // 00 00 00 01 -> Cs = I/O + P5OUT |= 0x01; // 00 00 00 01 -> Cs = High + P5DIR |= 0x0D; // 00 00 11 01 -> Dout, Clk, Cs = output + P5DIR &= ~0x02; // 00 00 00 10 -> Din = Input + P2SEL &= ~0x40; // 11 00 00 00 -> protect, detect = I/O + P2DIR &= ~0x40; // 11 00 00 00 -> protect, detect = input +} + +enum sd_init_ret +sd_init_card(sd_cache_t * pCache) +{ + enum sd_init_ret ret = SD_INIT_SUCCESS; + sd_csd_t csd; + uint16_t ccc; + sd_response_r3_t r3; + uint32_t blocklen, blocknr; + + if (!sd_detected()) + return SD_INIT_FAILED; + + uart_set_mode(UART_MODE_SPI); + + // reset card + if (!sd_reset()) { + ret = SD_INIT_FAILED; + goto sd_init_card_fail; + } + + // Test for hardware compatibility + if (!sd_send_cmd(SD_CMD_READ_OCR, SD_RESPONSE_TYPE_R3, NULL, &r3)) { + ret = SD_INIT_FAILED; + goto sd_init_card_fail; + } + + if ((r3.ocr & SD_V_MASK) != SD_V_MASK) { + ret = SD_INIT_NOTSUPP; + goto sd_init_card_fail; + } + + // Test for software compatibility + if (!sd_read_register(&csd, SD_CMD_SEND_CSD, sizeof (sd_csd_t))) { + ret = SD_INIT_FAILED; + goto sd_init_card_fail; + } + + blocklen = 1UL << SD_CSD_READ_BL_LEN(csd); + blocknr = ((unsigned long)(SD_CSD_C_SIZE(csd) + 1)) * (1 << (SD_CSD_C_MULT(csd) + 2)); + + printf("SD block length: %lu\n", (unsigned long)blocklen); + printf("SD block number: %lu\n", (unsigned long)blocknr); + + ccc = SD_CSD_CCC(csd); + if ((ccc & SD_DEFAULT_MINCCC) != SD_DEFAULT_MINCCC) { + ret = SD_INIT_NOTSUPP; + goto sd_init_card_fail; + } + +sd_init_card_fail: + uart_unlock(UART_MODE_SPI); + if (ret != SD_INIT_SUCCESS) + return ret; + + // state + sd_state.MinBlockLen_bit = 9; + sd_state.MaxBlockLen_bit = SD_CSD_READ_BL_LEN(csd); + sd_state.Flags = 0; + + if (SD_CSD_READ_PARTIAL(csd)) { + sd_state.MinBlockLen_bit = 0; + sd_state.Flags |= SD_READ_PARTIAL; + } + + if (SD_CSD_WRITE_PARTIAL(csd)) + sd_state.Flags |= SD_WRITE_PARTIAL; + sd_state.BlockLen_bit = 9; + sd_state.BlockLen = 1 << 9; + +#if SD_CACHE + if (pCache == NULL) + return SD_INIT_NOTSUPP; + + sd_state.Cache = pCache; + sd_cache_init(); +#endif + + return ret; +} + +void +sd_flush(void) +{ + if (uart_lock(UART_MODE_SPI)) { +#if SD_WRITE && SD_CACHE + sd_cache_flush(); +#endif +#if SD_WRITE && SPI_DMA_WRITE + sd_write_flush(); +#endif + uart_unlock(UART_MODE_SPI); + } +} + +void +sd_close(void) +{ + sd_flush(); +} + +uint8_t +sd_set_blocklength(const uint8_t blocklength_bit) +{ + uint8_t ret; + uint8_t arg[4]; + + // test if already set + if (blocklength_bit == sd_state.BlockLen_bit) + return sd_state.BlockLen_bit; + + // Wait for UART and switch to SPI mode + if (!uart_lock(UART_MODE_SPI)) + return sd_state.BlockLen_bit; + + ((uint16_t *) arg)[1] = 0; + ((uint16_t *) arg)[0] = 1 << blocklength_bit; + + // set blocklength command + if (sd_send_cmd(SD_CMD_SET_BLOCKLENGTH, SD_RESPONSE_TYPE_R1, arg, NULL)) { + sd_state.BlockLen_bit = blocklength_bit; + sd_state.BlockLen = ((uint16_t *) arg)[0]; + ret = blocklength_bit; + } else { + ret = SD_BLOCKLENGTH_INVALID; + } + + // unlock uart + uart_unlock(UART_MODE_SPI); + return ret; +} + +//@} + +/////////////////////////////////////////////////////////////////////////////// +// Public functions, Reading +/////////////////////////////////////////////////////////////////////////////// +uint16_t +sd_align_address(uint32_t * pAddress) +{ + uint16_t blMask = sd_state.BlockLen - 1; + uint16_t *lw = (uint16_t *) pAddress; + uint16_t offset = *lw & blMask; + + *lw &= ~blMask; + return offset; +} + +uint16_t +sd_read_block(void (*const pBuffer), const uint32_t address) +{ + if (!sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address)) + return FALSE; + spi_read(pBuffer, sd_state.BlockLen, TRUE); + + // receive CRC16 and finish + sd_read_stop(2); + return sd_state.BlockLen; +} + + +#if SD_READ_BYTE +bool +sd_read_byte(void *pBuffer, const uint32_t address) +{ + uint32_t blAdr = address; + uint16_t offset; // bytes from aligned address to start of first byte to keep + + if (sd_set_blocklength(0) == 0) + return sd_read_block(pBuffer, address); + + // align + offset = sd_align_address(&blAdr); + + // start + if (!sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address)) + return FALSE; + + // read + Spi_read(pBuffer, offset + 1, FALSE); + + // done + sd_read_stop(sd_state.BlockLen - offset - 1); + + return TRUE; +} + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Public functions, Writing +/////////////////////////////////////////////////////////////////////////////// +#if SD_WRITE +uint16_t +sd_write_finish(void) +{ + uint16_t r2; + uint8_t ret; + +#if SPI_DMA_WRITE + spi_dma_wait(); + spi_dma_lock = FALSE; +#endif + + // dummy crc + spi_idle(2); + + // receive data response (ZZS___ 3 bits crc response) + ret = spi_rx(); + while (ret & 0x80) + ret <<= 1; + ret = ((ret & 0x70) == 0x20); + + // wait for data to be written + sd_wait_standby(); + sd_unselect(); + + if (ret) { + // data transfer to sd card buffer was successful + // query for result of actual write operation + ret = sd_send_cmd(SD_CMD_SEND_STATUS, SD_RESPONSE_TYPE_R2, NULL, &r2); + if (ret & (r2 == 0)) + ret = sd_state.BlockLen; + } else { + // data transfer to sd card buffer failed + } + + // unlock uart (locked from every write operation) + uart_unlock(UART_MODE_SPI); + return ret; +} + +uint16_t +sd_write_flush(void) +{ +#if SPI_DMA_WRITE + if (!spi_dma_lock) + return 0; + return sd_write_finish(); +#else + return 0; +#endif +} + +uint16_t +sd_write_block_x(const uint32_t * pAddress, const void *pBuffer, bool incPtr) +{ + uint8_t r1, ret; + + // block write-access on write protection + if (sd_protected()) + return 0; + + // acquire uart + if (!uart_lock(UART_MODE_SPI)) + return 0; + + // start write + ret = sd_send_cmd(SD_CMD_WRITE_SINGLE_BLOCK, SD_RESPONSE_TYPE_R1, + pAddress, &r1); + if (!ret | r1) { + uart_unlock(UART_MODE_SPI); + return 0; + } + // write data + sd_select(); + spi_tx(0xFF); + SD_LED_WRITE_ON; + spi_write(pBuffer, sd_state.BlockLen, SD_TOKEN_WRITE, incPtr); + SD_LED_WRITE_OFF; + + // finish write +#if SPI_DMA_WRITE + spi_dma_lock = TRUE; + return sd_state.BlockLen; +#else + return sd_write_finish(); +#endif +} + +uint16_t +sd_set_block(const uint32_t address, const char (*const pChar)) +{ + return sd_write_block_x(&address, pChar, FALSE); +} + +uint16_t +sd_write_block(const uint32_t address, void const (*const pBuffer)) +{ + return sd_write_block_x(&address, pBuffer, TRUE); +} + + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Supporting functions +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Activate SD Card on SPI Bus + * @internal + */ +void +sd_select(void) +{ + P5OUT &= ~0x01; // Card Select +} + +/** + * @brief Deactivate SD Card on SPI Bus + * @internal + */ +void +sd_unselect(void) +{ + UART_WAIT_TXDONE(); + P5OUT |= 0x01; // Card Deselect + spi_rx(); +} + +/** + * @brief Wait for the card to enter standby state + * @internal + */ +bool +sd_wait_standby(void) +{ + sd_response_r1_t r1; + bool ret; + int i; + + spi_wait_token(0xFF, SD_TIMEOUT_READ); + for (i = 0; i < SD_TIMEOUT_IDLE; i++) { + ret = sd_get_op_cond(&r1); + if ((ret) && (r1.r1.in_idle_state == 0)) + return TRUE; + } + return FALSE; +} + + +/** + * @brief Resets the card and (hopefully) returns with the card in standby state + * @internal + */ +bool +sd_reset(void) +{ + int i; + bool ret; + sd_response_r1_t r1; + + for (i = 0; i < 4; i++) { + ret = sd_send_cmd(SD_CMD_GO_IDLE_STATE, SD_RESPONSE_TYPE_R1, NULL, &r1); + if (ret && r1.r1.illegal_cmd) { + sd_send_cmd(SD_CMD_STOP_TRANSMISSION, SD_RESPONSE_TYPE_R1, NULL, &r1); + ret = sd_send_cmd(SD_CMD_GO_IDLE_STATE, SD_RESPONSE_TYPE_R1, NULL, &r1); + } + ret = sd_wait_standby(); + if (ret) + return TRUE; + } + return FALSE; +} + + +/** + * @brief Reads operating condition from SD or MMC card. + * @internal + * @Note Should allow to find out the card type on first run if needed. + */ +bool +sd_get_op_cond(sd_response_r1_t * pResponse) +{ + bool ret; + + // SD style + ret = + sd_send_cmd(SD_CMD_APP_SECIFIC_CMD, SD_RESPONSE_TYPE_R1, NULL, pResponse); + if (ret) + ret = + sd_send_cmd(SD_ACMD_SEND_OP_COND, SD_RESPONSE_TYPE_R1, NULL, pResponse); + + // MMC style init + if (!ret) + ret = + sd_send_cmd(SD_CMD_SEND_OP_COND, SD_RESPONSE_TYPE_R1, NULL, pResponse); + if (*((uint8_t *) pResponse) & SD_R1_ERROR_MASK) + return FALSE; + return ret; +} + + +/** + * @brief Used to send all kinds of commands to the card and return the response. + * @internal + */ +bool +sd_send_cmd(const uint8_t command, const uint8_t response_type, + const void *pArg, void (*const pResponse)) +{ + uint8_t data; // rx buffer + int i; // loop counter + +#if SD_WRITE && SPI_DMA_WRITE + sd_write_flush(); +#endif + sd_select(); + + // send command (1 byte) + spi_tx(0x40 | command); + + // send argument (4 bytes) + if (pArg == NULL) { + for (i = 0; i < 4; i++) + spi_tx(0x00); + } else { + for (i = 3; i >= 0; i--) + spi_tx(((uint8_t *) pArg)[i]); + } + + // send CRC matching CMD0 (1 byte) + spi_tx(0x95); + + // wait for start bit + for (i = 0; i < SD_TIMEOUT_NCR; i++) { + data = spi_rx(); + if ((data & 0x80) == 0) + goto sd_send_cmd_response; + } + + // timeout ( i >= SD_TIMEOUT_NCR ) + // failed + sd_unselect(); + return FALSE; + +sd_send_cmd_response: + // start bit received, read response with size i + i = response_type - 1; + if (pResponse != NULL) { + + // copy response to response buffer + do { + ((uint8_t *) pResponse)[i] = data; + if (i == 0) + break; + data = spi_rx(); + i--; + } while (1); + } else { + // receive and ignore response + spi_idle(i); + } + + // done successfully + sd_unselect(); + return TRUE; +} + + +/** + * @brief Read Card Register + * @internal + */ +uint16_t +sd_read_register(void *pBuffer, uint8_t cmd, uint16_t size) +{ + if (!sd_read_start(cmd, 0)) { + return FALSE; + } + spi_read(pBuffer, size, TRUE); + sd_read_stop(2); + + return size; +} + + +/** + * @brief Begin block read operation + * @internal + */ +bool +sd_read_start(uint8_t cmd, uint32_t address) +{ + uint8_t r1; + uint8_t ret; + + if (!uart_lock(UART_MODE_SPI)) { + return FALSE; + } + ret = sd_send_cmd(cmd, SD_RESPONSE_TYPE_R1, &address, &r1); + if (!ret || r1) { + goto sd_read_start_fail; + } + + // Wait for start bit (0) + ret = sd_read_wait(); + if (ret) + return TRUE; + +sd_read_start_fail: + uart_unlock(UART_MODE_SPI); + return FALSE; +} + + +/** + * @brief Wait for beginning of data + * @internal + */ +bool +sd_read_wait(void) +{ + uint16_t i; // loop counter + uint8_t data; // rx buffer + + sd_select(); + for (i = 0; i < SD_TIMEOUT_READ; i++) { + data = spi_rx(); + if (data == SD_TOKEN_READ) { + + // token received, data bytes follow + SD_LED_READ_ON; + return TRUE; + } + +#if 0 + /* + * The following code handles error tokens. Since these are currently + * not used in the application they can just be ignored. Anyway this + * is still useful when debugging. + */ + + else if ((data != 0) && (data & SD_DATA_ERROR_TOKEN_MASK) == data) { + // data error token + spi_rx(); + break; + } +#endif + } + + // error or timeout + sd_unselect(); + return FALSE; +} + + +/** + * @brief Finished with reading, stop transfer + * @internal + */ +void +sd_read_stop(uint16_t count) +{ + + // finish block + crc + if (count) { + uint8_t dump; + + spi_read(&dump, count + 2, FALSE); + sd_unselect(); + } + SD_LED_READ_OFF; + + // wait for switch to standby mode + if (!sd_wait_standby()) + sd_reset(); + + // unlock uart (locked from sd_read_start) + uart_unlock(UART_MODE_SPI); +} diff --git a/platform/msb430/dev/sd/sd.h b/platform/msb430/dev/sd/sd.h new file mode 100644 index 000000000..4b6655164 --- /dev/null +++ b/platform/msb430/dev/sd/sd.h @@ -0,0 +1,358 @@ +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.h + * @ingroup libsd + * @brief MMC-/SD-Card library, Public interface + * + * @author Michael Baar + * @date Jan 2007 + * @version 0.2 + */ + +/** + * @ingroup libsd + * @{ + */ + +#ifndef SD_H +#define SD_H + +#define SD_BLOCKLENGTH_INVALID 0xFF +#define SD_WRITE_BLOCKLENGTH_BIT 9 +#define SD_WRITE_BLOCKLENGTH 0x200 + +/****************************************************************************** + * @name Setup, initialisation, configuration + * @{ + */ + +/** + * @name SD Flags + * @see sd_state_t + * @{ + */ +#define SD_READ_PARTIAL 0x80 +#define SD_WRITE_PARTIAL 0x40 + +/** @} */ + +#ifdef __TI_COMPILER_VERSION__ +#pragma pack(1) +#endif + +/** + * @brief Card Identification Register + */ +#ifndef __TI_COMPILER_VERSION__ +__attribute__ ((packed)) +#endif +typedef struct sd_cid { + uint8_t mid; + char oid[2]; + char pnm[5]; + uint8_t revision; + uint32_t psn; + uint16_t:4; + uint16_t mdt:12; + uint8_t crc7:7; + uint8_t:1; +} sd_cid_t; + +/** + * @name Card Specific Data register + * @{ + */ +typedef struct sd_csd { + uint8_t raw[16]; +} sd_csd_t; + +#define SD_CSD_READ_BL_LEN(csd) ((csd).raw[5] & 0x0F) // uchar : 4 +#define SD_CSD_READ_PARTIAL(csd) ((csd).raw[6] & 0x80) // bool +#define SD_CSD_CCC(csd) (((csd).raw[4]<<4) | ((csd).raw[5]>>4)) // uchar +#define SD_CSD_WRITE_PARTIAL(csd) ((csd).raw[13] & 0x04) // bool +#define SD_CSD_C_SIZE(csd) ((((csd).raw[6] & 0x03)<<10) | ((csd).raw[7]<<2) | ((csd).raw[8]>>6)) // uint : 12 +#define SD_CSD_C_MULT(csd) ((((csd).raw[9] & 0x03)<<1) | ((csd).raw[10]>>7)) // uchar : 4 + +/** @} */ + +#ifdef __TI_COMPILER_VERSION__ +#pragma pack() +#endif + +/* Card access library state */ +#define SD_CACHE_LOCKED 0x01 +#define SD_CACHE_DIRTY 0x02 + +typedef struct { + char buffer[SD_WRITE_BLOCKLENGTH]; + uint32_t address; + uint8_t state; +} sd_cache_t; + +typedef struct { + uint16_t MinBlockLen_bit:4; // minimum supported blocklength + uint16_t MaxBlockLen_bit:4; // maximum supported blocklength + uint16_t Flags:8; // feature flags + uint8_t BlockLen_bit; // currently selected blocklength as bit value (n where BlockLen is 2^n) + uint16_t BlockLen; // currently selected blocklength for reading and writing +#if SD_CACHE + sd_cache_t *Cache; +#endif +} sd_state_t; + +extern volatile sd_state_t sd_state; // Card access library state + +/** + * @brief Setup ports for sd card communication + * + * This function needs to be called once before any other library function. + * It invokes ::Spi_enable to configure UART1 for SPI communication. + * + * If you need to reconfigure the UART for other operations only call + * ::Spi_enable to return to SPI mode. ::sd_setup needs to be run only once. + */ +void sd_init(void); + +/** + * @brief Return value of ::sd_init function + */ +enum sd_init_ret { SD_INIT_SUCCESS = 0, SD_INIT_FAILED = 1, + SD_INIT_NOTSUPP = 2 }; + +/** + * @brief Initialize card and state + * @return one of sd_init_ret + * + * Initializes the memory card, checks supported voltage range and + * functionality. Initializes the global state struct sd_state. + * Should be invoked once immediately after ::sd_setup. + */ +enum sd_init_ret sd_init_card(sd_cache_t *); + +/** + * @brief Last operation to call when finished with using the card. + */ +void sd_close(void); + +/** + * @brief SD Card physically present? + * @return if no card present returns 0 + */ +#define sd_detected() ((P2IN & 0x40) == 0) + +/** + * @brief SD Card locked by switch? + * @return if card is not locked returns 0 + */ +#define sd_protected() ((P2IN & 0x80) != 0) + +/** + * @brief Set blocklength to 2 ^ n + * + * Tries to set the card's blocklength for reading and writing to any + * 2^n value, where n shall be between 0 and 11. + * Be aware that a card may or may not support different blocksizes. + * + * Since all read and write operations have to use blockaligned addresses + * and need to process complete blocks always try to use the optimal blocksize + * and let ::sd_read do the rest. If the blocklength is already set to the new + * value nothing is done. + * + * \Note + * The default blocklength is 512 (n=9). SD Cards usually support partial blocks + * with a blocklength of 1 to 512 (n=0 to n=9), MMC cards don't. + * Large cards support blocklength up to 2048 (n=11). + * The supported range of blocklengths can be read as n-value from + * sd_state.BlockLenMin_bit and sd_state.BlockLneMax_bit. The current value + * is available as n-value in sd_state.Blocsd_state.BlockLen_bit and as byte-value + * in sd_state.BlockLen. + * + * @param[in] blocklength_bit blocklength as n-value of 2^n + * + * @return Returns blocklength_bit if set operation was successful or + * SD_BLOCKLENGTH_INVALID otherwise. + * + */ +uint8_t sd_set_blocklength(const uint8_t blocklength_bit); + +/** + * @brief Align byte address to current blocklength + * @param[in,out] pAddress address to align, will be modified to be block aligned + * @return Offset from aligned address to original address + */ +uint16_t sd_align_address(uint32_t * pAddress); + +/** + * @brief Read one complete block from a block aligned address into buffer + * + * This function reads a single block of the currently set blocklength + * from a block aligned address. + * + * \Note: If address is not block aligned the card will respond with an error + * and no bytes will be read. + * + * @param[out] pBuffer Pointer to a buffer to which data is read. It should be least + * 1 byte large + * @param[in] address The address of the first byte that shall be read to pBuffer + * + * @return Number of bytes read (should always be = sd_state.BlockLen) + */ +uint16_t sd_read_block(void (*const pBuffer), const uint32_t address); + +#if SD_READ_BYTE +/** + * @brief Read one byte from any address + * This function reads a single byte from any address. It is optimized + * for best speed at any blocklength. + * \Note: blocklength is modified + * + * @param[out] pBuffer Pointer to a buffer to which data is read. It should be least + * 1 byte large + * @param[in] address The address of the byte that shall be read to pBuffer + * + * @return Number of bytes read (usually 1) + */ +bool sd_read_byte(void *pBuffer, const uint32_t address); + +#endif /* */ + +#if SD_WRITE +/** + * @brief Write one complete block at a block aligned address from buffer to card + * + * @param[in] address block aligned address to write to + * @param[in] pBuffer pointer to buffer with a block of data to write + * @return number of bytes successfully written, zero if write failed + * + * \Note + * Only supported block size for writing is usually 512 bytes. + */ +uint16_t sd_write_block(const uint32_t address, void const (*const pBuffer)); + +/** + * @brief Fill one complete block at a block aligned address with + * a single character. + * + * @param[in] address block aligned address to write to + * @param[in] pChar pointer to buffer with a character to write + * @return number of bytes successfully written, zero if write failed + * + * @note Use this for settings blocks to 0x00. + * Only supported block size for writing is usually 512 bytes. + */ +uint16_t sd_set_block(const uint32_t address, const char (*const pChar)); + +/** + * @brief Flush the DMA write buffer + * + * Wait for a running DMA write operation to finish + */ +uint16_t sd_write_flush(void); + +#endif + +#if SD_CACHE +#define SD_WAIT_LOCK(x) \ + while( x ->state & SD_CACHE_LOCKED ) { _NOP(); } + +#define SD_GET_LOCK(x) \ + do { \ + while( x ->state & SD_CACHE_LOCKED ) { _NOP(); }; \ + x ->state |= SD_CACHE_LOCKED; } \ + while(0) + +#define SD_FREE_LOCK(x) \ + do { \ + x ->state &= ~SD_CACHE_LOCKED; \ + } while(0) + +/** + * @brief Flush the sd cache + * + * Writes back the cache buffer, if it has been modified. Call this if + * a high level operation has finished and you want to store all data + * persistantly. The write back operation does not use timers. + */ +void sd_cache_flush(void); + +/** + * @brief Read a block into the cache buffer + * @internal + * + * You won't usually need this operation. + */ +sd_cache_t *sd_cache_read_block(const uint32_t * blAdr); + +#endif + +/** + * @brief Erase (clear) blocks of data + * @param[in] address Starting address of first block to erase + * @param[in] numBlocks Number of blocks to erase (starting at address) + * @return true if successful + * @note Data can only be erased in whole blocks. All bytes will be set + * predifined character (see CSD). Common cards use 0xFF. + */ +bool sd_erase_blocks(const uint32_t address, const uint16_t numBlocks); + +/** + * @brief Read card identification register (CID) + * @param[out] pCID Pointer to buffer for CID + * @return Number of bytes read (= size of CID) or 0 if failed + * + * @see ::sd_cid_t + */ +uint16_t sd_read_cid(sd_cid_t * pCID); + +/** + * @brief Read size of card + * @return Number of bytes available + * + * Reads the number of bytes in the card memory from the CSD register. + */ +uint32_t sd_get_size(void); + +#endif /* !SD_H */ + +/** @} */ diff --git a/platform/msb430/dev/sd/sd_cache.c b/platform/msb430/dev/sd/sd_cache.c new file mode 100644 index 000000000..519198ae1 --- /dev/null +++ b/platform/msb430/dev/sd/sd_cache.c @@ -0,0 +1,207 @@ + +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.cache.c + * @ingroup libsd + * @brief MMC-/SD-Card library, cached read and write + * + * @author Michael Baar + * @date Jan 2007 + * @version 0.2 + */ + +/** + * @addtogroup libsd + * @{ + */ +#include "sd_internals.h" +#include "sd.h" + +#if SD_CACHE +void +sd_cache_init(void) +{ + uint32_t adr = 0; + + sd_state.Cache->address = 1; + sd_state.Cache->state = 0; + + // pre-read first block + sd_cache_read_block(&adr); + SD_FREE_LOCK(sd_state.Cache); +} + +void +sd_cache_flush(void) +{ +#if SD_WRITE + SD_GET_LOCK(sd_state.Cache); + if (sd_state.Cache->state & SD_CACHE_DIRTY) { + sd_set_blocklength(SD_WRITE_BLOCKLENGTH_BIT); + sd_write_block(sd_state.Cache->address, sd_state.Cache->buffer); + sd_state.Cache->state &= ~SD_CACHE_DIRTY; + } + SD_FREE_LOCK(sd_state.Cache); +#endif +} + +sd_cache_t * +sd_cache_read_block(const uint32_t * pblAdr) +{ + SD_GET_LOCK(sd_state.Cache); + if (sd_state.Cache->address != *pblAdr) { + sd_set_blocklength(SD_WRITE_BLOCKLENGTH_BIT); + if (sd_state.Cache->state & SD_CACHE_DIRTY) { + sd_write_block(sd_state.Cache->address, sd_state.Cache->buffer); + sd_state.Cache->state &= ~SD_CACHE_DIRTY; + } + sd_state.Cache->address = *pblAdr; + if (!sd_read_block(sd_state.Cache->buffer, *pblAdr)) { + SD_FREE_LOCK(sd_state.Cache); + return FALSE; + } + } + return sd_state.Cache; +} + + +#if SD_READ_ANY +uint16_t +sd_read(void *pBuffer, uint32_t address, uint16_t size) +{ + uint16_t offset; // bytes from aligned address to start of first byte to keep + char *p; // pointer to current pos in receive buffer + uint16_t bytes_left; // num bytes to read + uint16_t read_count; // num bytes to read from current block + + // + // parameter processing + // + p = (char *) pBuffer; + bytes_left = size; + + // align to block + offset = sd_align_address(&address); + + // + // Data transfer + // + do { + // calculate block + if ((offset == 0) && (bytes_left >= sd_state.BlockLen)) { + read_count = sd_state.BlockLen; + sd_read_block(p, address); + } else { + sd_cache_read_block(&address); + read_count = bytes_left + offset; + if (read_count > sd_state.BlockLen) + read_count = sd_state.BlockLen - offset; + else + read_count = bytes_left; + memcpy(p, sd_state.Cache->buffer + offset, read_count); + SD_FREE_LOCK(sd_state.Cache); + } + bytes_left -= read_count; + if (bytes_left == 0) + return size; + p += read_count; + address += sd_state.BlockLen; + } while (1); +} + +#endif // SD_READ_ANY + +#if SD_WRITE +uint16_t +sd_write(uint32_t address, void *pBuffer, uint16_t size) +{ + uint16_t offset; // bytes from aligned address to start of first byte to keep + char *p; // pointer to current pos in receive buffer + uint16_t bytes_left; // num bytes to read + uint16_t read_count; // num bytes to read from current block + + // + // parameter processing + // + p = (char *) pBuffer; + bytes_left = size; + + // align to block + offset = sd_align_address(&address); + sd_set_blocklength(SD_WRITE_BLOCKLENGTH_BIT); + + // + // Data transfer + // + do { + + // calculate block + if ((offset == 0) && (bytes_left >= sd_state.BlockLen)) { + read_count = sd_state.BlockLen; + sd_write_block(address, p); + } else { + sd_cache_read_block(&address); + read_count = bytes_left + offset; + if (read_count > sd_state.BlockLen) + read_count = sd_state.BlockLen - offset; + + else + read_count = bytes_left; + memcpy(sd_state.Cache->buffer + offset, p, read_count); + SD_FREE_LOCK(sd_state.Cache); + } + if (bytes_left == 0) + return size; + p += read_count; + bytes_left -= read_count; + address += sd_state.BlockLen; + } while (1); +} + + +#endif // SD_WRITE + +#endif // SD_CACHE + +/** @} */ diff --git a/platform/msb430/dev/sd/sd_erase.c b/platform/msb430/dev/sd/sd_erase.c new file mode 100644 index 000000000..a8d9020d2 --- /dev/null +++ b/platform/msb430/dev/sd/sd_erase.c @@ -0,0 +1,85 @@ + +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.erase.c + * @ingroup libsd + * @brief MMC-/SD-Card library, Block erase + * + * @author Michael Baar + * @date Feb 2007 + * @version 0.2 + */ + +/** + * @addtogroup libsd + * @{ + */ +#include "sd_internals.h" +#include "sd.h" + +bool +sd_erase_blocks(uint32_t address, uint16_t numBlocks) +{ + uint8_t ret, r1; + uint32_t endAdr; + + if (sd_protected()) + return FALSE; + ret = + sd_send_cmd(SD_CMD_ERASE_WR_BLK_START_ADDR, SD_RESPONSE_TYPE_R1, + &address, &r1); + if (!ret | r1) + return FALSE; + endAdr = (numBlocks - 1) * sd_state.BlockLen; + endAdr += address; + ret = + sd_send_cmd(SD_CMD_ERASE_WR_BLK_END_ADDR, SD_RESPONSE_TYPE_R1, &endAdr, + &r1); + if (!ret | r1) + return FALSE; + ret = sd_send_cmd(SD_CMD_ERASE, SD_RESPONSE_TYPE_R1, NULL, &r1); + return ret; +} + +/** @} */ diff --git a/platform/msb430/dev/sd/sd_info.c b/platform/msb430/dev/sd/sd_info.c new file mode 100644 index 000000000..2e9a4edec --- /dev/null +++ b/platform/msb430/dev/sd/sd_info.c @@ -0,0 +1,86 @@ + +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.info.c + * @ingroup libsd + * @brief MMC-/SD-Card library, Additional Information + * + * @author Michael Baar + * @date Feb 2007 + * @version 0.2 + */ + +/** + * @addtogroup libsd + * @{ + */ +#include "sd_internals.h" +#include "sd.h" + +uint16_t +sd_read_cid(sd_cid_t * pCID) +{ + return sd_read_register(pCID, SD_CMD_SEND_CID, sizeof (sd_cid_t)); +} + +unsigned long +sd_get_size(void) +{ + uint32_t size = 0; + + if (uart_lock(UART_MODE_SPI)) { + sd_csd_t csd; + + if (sd_read_register(&csd, SD_CMD_SEND_CSD, sizeof (sd_csd_t))) { + size = SD_CSD_C_SIZE(csd) + 1; + size <<= SD_CSD_C_MULT(csd); + size <<= 2; + size <<= sd_state.MaxBlockLen_bit; + } + uart_unlock(UART_MODE_SPI); + } + return size; +} + +/** @} */ diff --git a/platform/msb430/dev/sd/sd_internals.h b/platform/msb430/dev/sd/sd_internals.h new file mode 100644 index 000000000..ae82eb70e --- /dev/null +++ b/platform/msb430/dev/sd/sd_internals.h @@ -0,0 +1,233 @@ + +/* +Copyright 2007, Freie Universitaet Berlin. All rights reserved. + +These sources were developed at the Freie Universität Berlin, Computer +Systems and Telematics group. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Freie Universitaet Berlin (FUB) 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 FUB and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall FUB 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 implementation was developed by the CST group at the FUB. + +For documentation and questions please use the web site +http://scatterweb.mi.fu-berlin.de and the mailinglist +scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). +Berlin, 2007 +*/ + +/** + * @file ScatterWeb.sd.internals.h + * @ingroup libsd + * @brief MMC-/SD-Card library + * + * @author Michael Baar + * @date Jan 2007 + * @version 0.2 + * + * Header file containing private declarations used MMC-/SD-Card library. + */ + +#ifndef SD_INTERNALS_H +#define SD_INTERNALS_H + +#include +#include "contiki-msb430.h" + +#define RETF(x) if( ! x ) return false; +#define MIN(x, y) ( x < y ) ? x : y + +/** + * @name SD Card SPI responses + */ + +struct sd_response_r1_bits { + uint8_t in_idle_state:1; + uint8_t erase_reset:1; + uint8_t illegal_cmd:1; + uint8_t crc_err:1; + uint8_t erase_seq_err:1; + uint8_t address_err:1; + uint8_t param_err:1; + uint8_t start_bit:1; +}; + +struct sd_response_r2_bits { + uint8_t card_locked:1; + uint8_t write_failed:1; + uint8_t unspecified_err:1; + uint8_t controller_err:1; + uint8_t ecc_failed:1; + uint8_t protect_violation:1; + uint8_t erase_param:1; + uint8_t out_of_range:1; +}; + +struct sd_read_error_token { + uint8_t unspecified_err:1; + uint8_t controller_err:1; + uint8_t ecc_failed:1; + uint8_t out_of_range:1; + uint8_t card_locked:1; + uint8_t:3; +}; + +struct sd_data_error_token { + uint8_t error:1; + uint8_t cc_error:1; + uint8_t ecc_error:1; + uint8_t out_of_range:1; + uint8_t:4; // always 0 (-> SD_DATA_ERROR_TOKEN_MASK) +}; + +typedef struct sd_response_r1 { + struct sd_response_r1_bits r1; +} sd_response_r1_t; + +typedef struct sd_response_r2 { + struct sd_response_r1_bits r1; + struct sd_response_r2_bits r2; +} sd_response_r2_t; + +typedef struct sd_response_r3 { + uint32_t ocr; + struct sd_response_r1_bits r1; +} sd_response_r3_t; + +typedef struct sd_read_error_token sd_read_error_token_t; +typedef struct sd_data_error_token sd_data_error_t; + +#define SD_DATA_ERROR_TOKEN_MASK 0x0F // mask for error token +#define SD_R1_ERROR_MASK 0x7C // mask for error bits in r1 response +///@} + +/** + * @name Private interface + */ + +// Read operating condition +bool sd_get_op_cond(sd_response_r1_t * pResponse); + +// Reset card +bool sd_reset(void); + +// Send command and read response +bool sd_send_cmd(const uint8_t command, const uint8_t response_type, + const void *pArg, void (*const pResponse)); + +// Select card +void sd_select(void); + +// Unselect card +void sd_unselect(void); + +// Wait for card to leave idle mode +bool sd_wait_standby(void); + +// Read card register +uint16_t sd_read_register(void (*const pBuffer), const uint8_t cmd, + const uint16_t size); + +// Begin block read operation +bool sd_read_start(const uint8_t cmd, const uint32_t address); + +// Wait for begin of data +bool sd_read_wait(void); + +// Cancel block read operation +void sd_read_stop(const uint16_t count); + +#if SD_WRITE +uint16_t sd_write_block_x(const uint32_t * pAddress, const void * pBuffer, + bool incPtr); + +#endif /* */ + +#if SD_CACHE +void sd_cache_init(void); +void sd_cache_flush(void); + +#endif /* */ +///@} + +#define SD_TOKEN_READ 0xFE +#define SD_TOKEN_WRITE 0xFE +#define SD_TOKEN_ZP 0xFF + +#define SD_TIMEOUT_IDLE 1000 // # of poll-cycles for reset procedure (takes some time) +#define SD_TIMEOUT_READ 20000 +#define SD_TIMEOUT_NCR 8 // 8-64 cycles + +#define SD_V_MASK 0x003E0000 // 3,4 - 2,9 V + +#define SD_RESPONSE_TYPE_R1 1 +#define SD_RESPONSE_TYPE_R2 2 +#define SD_RESPONSE_TYPE_R3 5 + +/** + * @name Command classes + * @{ + */ +#define SD_CCC_BASIC BIT0 +#define SD_CCC_BLOCK_READ BIT2 +#define SD_CCC_BLOCK_WRITE BIT4 +#define SD_CCC_APP_SPECIFIC BIT8 + +#if SD_WRITE +#define SD_DEFAULT_MINCCC (SD_CCC_BASIC | \ + SD_CCC_BLOCK_READ | SD_CCC_APP_SPECIFIC | SD_CCC_BLOCK_WRITE) +#else /* */ +#define SD_DEFAULT_MINCCC (SD_CCC_BASIC | \ + SD_CCC_BLOCK_READ | SD_CCC_APP_SPECIFIC) +#endif /* */ +//@} + +/** + * @name Commands + * @{ + */ +#define SD_CMD_GO_IDLE_STATE 0 // R1 "reset command" +#define SD_CMD_SEND_OP_COND 1 // R1 (MMC only!) +#define SD_CMD_SEND_CSD 9 // R1 +#define SD_CMD_SEND_CID 10 // R1 +#define SD_CMD_STOP_TRANSMISSION 12 // R1b +#define SD_CMD_SEND_STATUS 13 // R2 +#define SD_CMD_SET_BLOCKLENGTH 16 +#define SD_CMD_READ_SINGLE_BLOCK 17 // R1 +#define SD_CMD_READ_MULTI_BLOCK 18 // R1 +#define SD_CMD_WRITE_SINGLE_BLOCK 24 // R1 +#define SD_CMD_ERASE_WR_BLK_START_ADDR 32 // R1 +#define SD_CMD_ERASE_WR_BLK_END_ADDR 33 // R1 +#define SD_CMD_ERASE 38 // R1b +#define SD_CMD_APP_SECIFIC_CMD 55 +#define SD_CMD_READ_OCR 58 // R3 OCR = voltage table + +#define SD_ACMD_SEND_OP_COND 41 // R1 +//@} + +#endif /* !SD_INTERNALS_H */