diff --git a/platform/msb430/dev/sd/sd.c b/platform/msb430/dev/sd/sd.c index a24ed6b0d..9e6fdb9a7 100644 --- a/platform/msb430/dev/sd/sd.c +++ b/platform/msb430/dev/sd/sd.c @@ -41,127 +41,135 @@ scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). Berlin, 2007 */ + /** - * @file ScatterWeb.sd.c + * @file ScatterWeb.Sd.c * @ingroup libsd * @brief MMC-/SD-Card library * * @author Michael Baar - * @date Jan 2007 - * @version 0.2 + * @version $Revision: 1.2 $ + * + * $Id: sd.c,v 1.2 2008/03/28 15:58:43 nvt-se Exp $ * * 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() +sd_init(void) { - 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 + // depending on the system global variables may not get initialised on startup + memset((void *)&sd_state, 0, sizeof (sd_state)); + + // initialize io ports + sd_init_platform(); } + 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; + struct sd_csd csd; + uint16_t ccc = 0; + int resetcnt; + struct sd_response_r3 r3; - if (!sd_detected()) + if (!sd_detected()) { + return SD_INIT_NOCARD; + } + + if (sd_state.Flags & SD_INITIALIZED) { + return SD_INIT_SUCCESS; + } + + // Wait for UART and switch to SPI mode + if (!uart_lock_wait(UART_MODE_SPI)) { return SD_INIT_FAILED; - - uart_set_mode(UART_MODE_SPI); + } // reset card - if (!sd_reset()) { + resetcnt = _sd_reset(&r3); + + if (resetcnt >= SD_RESET_RETRY_COUNT) { 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))) { + if (!_sd_read_register(&csd, SD_CMD_SEND_CSD, sizeof (struct sd_csd))) { 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; +sd_init_card_fail: + sdspi_unselect(); + + uart_unlock(UART_MODE_SPI); +#ifdef LOG_VERBOSE + LOG_VERBOSE("(sd_init) result:%u, resetcnt:%i OCR:%.8lx, CCC:%.4x", + ret, resetcnt, r3.ocr, ccc); +#endif + 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; - + sd_state.Flags = SD_INITIALIZED; if (SD_CSD_READ_PARTIAL(csd)) { sd_state.MinBlockLen_bit = 0; sd_state.Flags |= SD_READ_PARTIAL; } - if (SD_CSD_WRITE_PARTIAL(csd)) + 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) + if (pCache == NULL) { return SD_INIT_NOTSUPP; - + } sd_state.Cache = pCache; - sd_cache_init(); + _sd_cache_init(); #endif return ret; } + void sd_flush(void) { if (uart_lock(UART_MODE_SPI)) { #if SD_WRITE && SD_CACHE - sd_cache_flush(); + _sd_cache_flush(); #endif #if SD_WRITE && SPI_DMA_WRITE sd_write_flush(); @@ -170,12 +178,17 @@ sd_flush(void) } } + void sd_close(void) { sd_flush(); + + // reset state + memset((void *)&sd_state, 0, sizeof (sd_state)); } + uint8_t sd_set_blocklength(const uint8_t blocklength_bit) { @@ -183,18 +196,20 @@ sd_set_blocklength(const uint8_t blocklength_bit) uint8_t arg[4]; // test if already set - if (blocklength_bit == sd_state.BlockLen_bit) + 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)) + if (!uart_lock_wait(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)) { + if (_sd_send_cmd(SD_CMD_SET_BLOCKLENGTH, SD_RESPONSE_SIZE_R1, arg, NULL)) { sd_state.BlockLen_bit = blocklength_bit; sd_state.BlockLen = ((uint16_t *) arg)[0]; ret = blocklength_bit; @@ -207,31 +222,37 @@ sd_set_blocklength(const uint8_t blocklength_bit) return ret; } + //@} /////////////////////////////////////////////////////////////////////////////// // Public functions, Reading /////////////////////////////////////////////////////////////////////////////// uint16_t -sd_align_address(uint32_t * pAddress) +sd_AlignAddress(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)) + if (!_sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address)) { return FALSE; - spi_read(pBuffer, sd_state.BlockLen, TRUE); + } + + sdspi_read(pBuffer, sd_state.BlockLen, TRUE); // receive CRC16 and finish - sd_read_stop(2); + _sd_read_stop(2); + return sd_state.BlockLen; } @@ -240,131 +261,257 @@ sd_read_block(void (*const pBuffer), const uint32_t address) 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) + if (sd_set_blocklength(0) == 0) { return sd_read_block(pBuffer, address); + } else { + uint32_t blAdr = address; + uint16_t offset; // bytes from aligned address to start of first byte to keep + // align + offset = sd_AlignAddress(&blAdr); - // align - offset = sd_align_address(&blAdr); + // start + if (!_sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address)) { + return FALSE; + } - // start - if (!sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address)) - return FALSE; + // read + Spi_read(pBuffer, offset + 1, FALSE); - // read - Spi_read(pBuffer, offset + 1, FALSE); - - // done - sd_read_stop(sd_state.BlockLen - offset - 1); + // done + _sd_read_stop(sd_state.BlockLen - offset - 1); + } return TRUE; } - #endif +#if SD_READ_ANY && !SD_CACHE +unsigned int +sd_read(void *pBuffer, unsigned long address, unsigned int size) +{ + unsigned char *p; // pointer to current pos in receive buffer + unsigned int offset; // bytes from aligned address to start of first byte to keep + unsigned int read_count; // num bytes to read in one iteration + bool dump_flag; // number of bytes to dump in last iteration + unsigned int num_bytes_read; // number of bytes read into receive buffer + unsigned char ret; + + // + // parameter processing + // + if (size == 0) { + return FALSE; + } + + // align to block + offset = sd_AlignAddress(&address); + + if ((offset == 0) && (sd_state.BlockLen == size)) { + // best case: perfectly block aligned, no chunking + // -> do shortcut + return sd_read_block(pBuffer, address); + } + // calculate first block + if (size > sd_state.BlockLen) { + read_count = sd_state.BlockLen; + } else { + read_count = size; + } + // + // Data transfer + // + + // request data transfer + ret = _sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address); + + RETF(ret); + + // run to offset + if (offset) { + sdspi_read(pBuffer, offset, FALSE); // dump till offset + dump_flag = ((read_count + offset) < sd_state.BlockLen); + if (!dump_flag) { + read_count = sd_state.BlockLen - offset; // max bytes to read from first block + } + } else { + dump_flag = (read_count < sd_state.BlockLen); + } + + // + // block read loop + // + num_bytes_read = 0; + p = pBuffer; + + do { + // whole block will be processed + size -= read_count; // global counter + + // read to receive buffer + sdspi_read(p, read_count, TRUE); + + p += read_count; // increment buffer pointer + num_bytes_read += read_count; + + // finish block + if (dump_flag) { + // cancel remaining bytes (last iteration) + _sd_read_stop(sd_state.BlockLen - read_count - offset); + break; + // unselect is included in send_cmd + } else { + sdspi_idle(2); // receive CRC16 + if (size != 0) { + // address calculation for next block + offset = 0; + address += sd_state.BlockLen; + if (size > sd_state.BlockLen) { + read_count = sd_state.BlockLen; + dump_flag = FALSE; + } else { + read_count = size; + dump_flag = TRUE; + } + + sdspi_unselect(); + ret = _sd_read_start(SD_CMD_READ_SINGLE_BLOCK, address); + RETF(ret); + } else { + // finished + _sd_read_stop(0); + break; + } + } + } while (1); + + return num_bytes_read; +} + +#endif // SD_READ_ANY + /////////////////////////////////////////////////////////////////////////////// // Public functions, Writing /////////////////////////////////////////////////////////////////////////////// #if SD_WRITE -uint16_t -sd_write_finish(void) +enum sd_write_ret +_sd_write_finish(void) { uint16_t r2; uint8_t ret; + enum sd_write_ret result = SD_WRITE_STORE_ERR; + uint16_t i; #if SPI_DMA_WRITE - spi_dma_wait(); - spi_dma_lock = FALSE; + sdspi_dma_wait(); + sdspi_dma_lock = FALSE; #endif // dummy crc - spi_idle(2); + sdspi_idle(2); // receive data response (ZZS___ 3 bits crc response) - ret = spi_rx(); - while (ret & 0x80) - ret <<= 1; - ret = ((ret & 0x70) == 0x20); + for (i = 0; i < SD_TIMEOUT_NCR; i++) { + ret = sdspi_rx(); + if ((ret > 0) && (ret < 0xFF)) { + while (ret & 0x80) { + ret <<= 1; + } + ret = ((ret & 0x70) == 0x20); + break; + } + } // wait for data to be written - sd_wait_standby(); - sd_unselect(); + _sd_wait_standby(NULL); + sdspi_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; + ret = _sd_send_cmd(SD_CMD_SEND_STATUS, SD_RESPONSE_SIZE_R2, NULL, &r2); + if (ret && (r2 == 0)) { + result = SD_WRITE_SUCCESS; + } } else { // data transfer to sd card buffer failed } // unlock uart (locked from every write operation) uart_unlock(UART_MODE_SPI); - return ret; + + return result; + } -uint16_t +enum sd_write_ret sd_write_flush(void) { #if SPI_DMA_WRITE - if (!spi_dma_lock) - return 0; - return sd_write_finish(); + if (!sdspi_dma_lock) { + return SD_WRITE_DMA_ERR; + } else { + return _sd_write_finish(); + } #else - return 0; + return SD_WRITE_SUCCESS; #endif } -uint16_t -sd_write_block_x(const uint32_t * pAddress, const void *pBuffer, bool incPtr) + +enum sd_write_ret +_sd_write_block(const uint32_t * pAddress, const void *pBuffer, int increment) { uint8_t r1, ret; // block write-access on write protection - if (sd_protected()) - return 0; + if (sd_protected()) { + return SD_WRITE_PROTECTED_ERR; + } // acquire uart - if (!uart_lock(UART_MODE_SPI)) - return 0; + if (!uart_lock_wait(UART_MODE_SPI)) { + return SD_WRITE_INTERFACE_ERR; + } // start write - ret = sd_send_cmd(SD_CMD_WRITE_SINGLE_BLOCK, SD_RESPONSE_TYPE_R1, + SD_LED_WRITE_ON; + r1 = 0; + ret = _sd_send_cmd(SD_CMD_WRITE_SINGLE_BLOCK, SD_RESPONSE_SIZE_R1, pAddress, &r1); if (!ret | r1) { uart_unlock(UART_MODE_SPI); - return 0; +printf("r1 = %u\n", r1); + SD_LED_WRITE_OFF; + return SD_WRITE_COMMAND_ERR; } // write data - sd_select(); - spi_tx(0xFF); - SD_LED_WRITE_ON; - spi_write(pBuffer, sd_state.BlockLen, SD_TOKEN_WRITE, incPtr); + sdspi_select(); + sdspi_tx(0xFF); + sdspi_tx(SD_TOKEN_WRITE); + sdspi_write(pBuffer, sd_state.BlockLen, increment); + SD_LED_WRITE_OFF; // finish write #if SPI_DMA_WRITE - spi_dma_lock = TRUE; - return sd_state.BlockLen; + sdspi_dma_lock = TRUE; + return SD_WRITE_SUCCESS; #else - return sd_write_finish(); + return _sd_write_finish(); #endif } -uint16_t +enum sd_write_ret sd_set_block(const uint32_t address, const char (*const pChar)) { - return sd_write_block_x(&address, pChar, FALSE); + return _sd_write_block(&address, pChar, FALSE); } -uint16_t + +enum sd_write_ret sd_write_block(const uint32_t address, void const (*const pBuffer)) { - return sd_write_block_x(&address, pBuffer, TRUE); + return _sd_write_block(&address, pBuffer, TRUE); } @@ -374,276 +521,254 @@ sd_write_block(const uint32_t address, void const (*const pBuffer)) // 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. + * \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) +inline bool _sd_get_op_cond(struct sd_response_r1 * 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); + ret = _sd_send_cmd(SD_CMD_APP_SECIFIC_CMD, SD_RESPONSE_SIZE_R1, NULL, + pResponse); + + if (ret) { + uint32_t arg = SD_V_MASK; + ret = _sd_send_cmd(SD_ACMD_SEND_OP_COND, SD_RESPONSE_SIZE_R1, &arg, + pResponse); + } else { + // MMC style init + ret = _sd_send_cmd(SD_CMD_SEND_OP_COND, SD_RESPONSE_SIZE_R1, NULL, + pResponse); + if (*((uint8_t *) pResponse) & SD_R1_ERROR_MASK) { + ret = FALSE; + } + } - // 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 Wait for the card to enter standby state + * \internal + */ +bool +_sd_wait_standby(struct sd_response_r3 * pOpCond) +{ + bool ret; + int i = SD_TIMEOUT_IDLE; + struct sd_response_r3 opCond; + struct sd_response_r3 *pR3 = pOpCond; + + if (pR3 == NULL) { + pR3 = &opCond; + } + + sdspi_wait_token(0xFF, 0xFF, 0xFF, SD_TIMEOUT_NCR); + + do { + ret = _sd_get_op_cond((struct sd_response_r1 *)pR3); + if (ret && (pR3->r1.in_idle_state == 0)) { + ret = _sd_send_cmd(SD_CMD_READ_OCR, SD_RESPONSE_SIZE_R3, NULL, pR3); + if (ret && !SD_OCR_BUSY(pR3->ocr)) { + return TRUE; + } + } + i--; + } while (i); + + return FALSE; +} + +/** + * @brief Resets the card and (hopefully) returns with the card in standby state + * \internal + */ +int +_sd_reset(struct sd_response_r3 *pOpCond) +{ + int i; + bool ret; + struct sd_response_r1 r1; + + for (i = 0; i < SD_RESET_RETRY_COUNT; i++) { + ret = _sd_send_cmd(SD_CMD_GO_IDLE_STATE, SD_RESPONSE_SIZE_R1, NULL, &r1); + if (ret == 0 || r1.illegal_cmd) { + _sd_send_cmd(SD_CMD_STOP_TRANSMISSION, SD_RESPONSE_SIZE_R1, NULL, &r1); + } else { + ret = _sd_wait_standby(pOpCond); + if (ret) { + break; + } + } + } + + return i; +} /** * @brief Used to send all kinds of commands to the card and return the response. - * @internal + * \internal */ bool -sd_send_cmd(const uint8_t command, const uint8_t response_type, - const void *pArg, void (*const pResponse)) +_sd_send_cmd(const uint8_t command, + const int response_size, + const void *pArg, void (*const pResponse)) { + uint8_t cmd[6] = { + 0x40, 0, 0, 0, 0, 0x95 + }; 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]); + sdspi_select(); + cmd[0] |= command; + if (pArg != NULL) { + cmd[1] = ((uint8_t *) pArg)[3]; + cmd[2] = ((uint8_t *) pArg)[2]; + cmd[3] = ((uint8_t *) pArg)[1]; + cmd[4] = ((uint8_t *) pArg)[0]; } - // send CRC matching CMD0 (1 byte) - spi_tx(0x95); + sdspi_write(cmd, 6, 1); // wait for start bit - for (i = 0; i < SD_TIMEOUT_NCR; i++) { - data = spi_rx(); - if ((data & 0x80) == 0) - goto sd_send_cmd_response; - } + i = SD_TIMEOUT_NCR; + do { + data = sdspi_rx(); + if ((data & 0x80) == 0) { + goto _sd_send_cmd_response; + } + } while (i); - // timeout ( i >= SD_TIMEOUT_NCR ) - // failed - sd_unselect(); - return FALSE; + goto sd_send_cmd_fail; -sd_send_cmd_response: +_sd_send_cmd_response: // start bit received, read response with size i - i = response_type - 1; + i = response_size - 1; if (pResponse != NULL) { - // copy response to response buffer do { ((uint8_t *) pResponse)[i] = data; - if (i == 0) + if (i == 0) { break; - data = spi_rx(); + } + + data = sdspi_rx(); i--; } while (1); } else { // receive and ignore response - spi_idle(i); + sdspi_read(&data, i, 0); } // done successfully - sd_unselect(); - return TRUE; -} + sdspi_unselect(); + return TRUE; + +sd_send_cmd_fail: + // failed + //sdspi_unselect(); + return FALSE; + +} /** * @brief Read Card Register - * @internal + * \internal */ uint16_t -sd_read_register(void *pBuffer, uint8_t cmd, uint16_t size) +_sd_read_register(void *pBuffer, uint8_t cmd, uint16_t size) { - if (!sd_read_start(cmd, 0)) { + if (!_sd_read_start(cmd, 0)) { return FALSE; } - spi_read(pBuffer, size, TRUE); - sd_read_stop(2); + + sdspi_read(pBuffer, size, TRUE); + _sd_read_stop(2); return size; } - /** * @brief Begin block read operation - * @internal + * \internal */ bool -sd_read_start(uint8_t cmd, uint32_t address) +_sd_read_start(uint8_t cmd, uint32_t address) { uint8_t r1; uint8_t ret; + uint16_t i; - if (!uart_lock(UART_MODE_SPI)) { + // aquire uart + if (!uart_lock_wait(UART_MODE_SPI)) { return FALSE; } - ret = sd_send_cmd(cmd, SD_RESPONSE_TYPE_R1, &address, &r1); + + ret = _sd_send_cmd(cmd, SD_RESPONSE_SIZE_R1, &address, &r1); if (!ret || r1) { - goto sd_read_start_fail; + goto _sd_read_start_fail; } // Wait for start bit (0) - ret = sd_read_wait(); - if (ret) - return TRUE; + sdspi_select(); -sd_read_start_fail: + i = sdspi_wait_token(0xFF, 0xFF, SD_TOKEN_READ, SD_TIMEOUT_READ); + + if (i < SD_TIMEOUT_READ) { + // token received, data bytes follow + SD_LED_READ_ON; + + /* + 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 + sdspi_rx(); + break; + } */ + return TRUE; + } else { + // error or timeout + } + +_sd_read_start_fail: + sdspi_unselect(); 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 + * \internal */ void -sd_read_stop(uint16_t count) +_sd_read_stop(uint16_t count) { - // finish block + crc if (count) { uint8_t dump; - spi_read(&dump, count + 2, FALSE); - sd_unselect(); + sdspi_read(&dump, count + 2, FALSE); + sdspi_unselect(); } + SD_LED_READ_OFF; // wait for switch to standby mode - if (!sd_wait_standby()) - sd_reset(); + if (!_sd_wait_standby(NULL)) { + _sd_reset(NULL); + } - // unlock uart (locked from sd_read_start) + // 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 index 4b6655164..8f57621a4 100644 --- a/platform/msb430/dev/sd/sd.h +++ b/platform/msb430/dev/sd/sd.h @@ -1,3 +1,4 @@ + /* Copyright 2007, Freie Universitaet Berlin. All rights reserved. @@ -41,13 +42,14 @@ Berlin, 2007 */ /** - * @file ScatterWeb.sd.h + * @file ScatterWeb.Sd.h * @ingroup libsd * @brief MMC-/SD-Card library, Public interface * * @author Michael Baar - * @date Jan 2007 - * @version 0.2 + * @version $Revision: 1.2 $ + * + * $Id: sd.h,v 1.2 2008/03/28 15:58:43 nvt-se Exp $ */ /** @@ -55,25 +57,29 @@ Berlin, 2007 * @{ */ -#ifndef SD_H -#define SD_H +#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 + * @brief SD Flags * @see sd_state_t * @{ */ -#define SD_READ_PARTIAL 0x80 -#define SD_WRITE_PARTIAL 0x40 +enum sd_state_flags { + SD_READ_PARTIAL = 0x80, + SD_WRITE_PARTIAL = 0x40, + SD_INITIALIZED = 0x01 +}; /** @} */ @@ -87,61 +93,65 @@ Berlin, 2007 #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; +#if defined(__MSP430GCC__) + __attribute__ ((packed)) +#endif + 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; + }; +#ifdef __TI_COMPILER_VERSION__ +#pragma pack() +#endif /** * @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 + struct sd_csd { + uint8_t raw[16]; + }; +#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 */ +/// 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 + 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; + sd_cache_t *Cache; #endif -} sd_state_t; + } sd_state_t; -extern volatile sd_state_t sd_state; // Card access library state + extern volatile sd_state_t sd_state; ///< Card access library state + +/** + * @brief Library initialisation + */ + void sd_Init(void); /** * @brief Setup ports for sd card communication @@ -152,13 +162,30 @@ extern volatile sd_state_t sd_state; // Card access library state * 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); + void sd_init_platform(void); /** * @brief Return value of ::sd_init function */ -enum sd_init_ret { SD_INIT_SUCCESS = 0, SD_INIT_FAILED = 1, - SD_INIT_NOTSUPP = 2 }; + enum sd_init_ret { + SD_INIT_SUCCESS = 0, + SD_INIT_NOCARD = 1, + SD_INIT_FAILED = 2, + SD_INIT_NOTSUPP = 3 + }; + +/** + * @brief Return value of write functions + * @see ::sd_write, ::sd_write_block + */ + enum sd_write_ret { + SD_WRITE_SUCCESS = 0, ///< writing successfull + SD_WRITE_PROTECTED_ERR = 1, ///< card write protected + SD_WRITE_INTERFACE_ERR = 2, ///< error in UART SPI interface + SD_WRITE_COMMAND_ERR = 3, ///< error in write command or command arguments (e.g. target address) + SD_WRITE_STORE_ERR = 4, ///< storing written data to persistant memory on card failed + SD_WRITE_DMA_ERR = 5 + }; /** * @brief Initialize card and state @@ -168,12 +195,12 @@ enum sd_init_ret { SD_INIT_SUCCESS = 0, SD_INIT_FAILED = 1, * 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 *); + enum sd_init_ret sd_init_card(sd_cache_t * pCache); /** * @brief Last operation to call when finished with using the card. */ -void sd_close(void); + void sd_close(void); /** * @brief SD Card physically present? @@ -214,14 +241,14 @@ void sd_close(void); * SD_BLOCKLENGTH_INVALID otherwise. * */ -uint8_t sd_set_blocklength(const uint8_t blocklength_bit); + 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); + uint16_t sd_AlignAddress(uint32_t * pAddress); /** * @brief Read one complete block from a block aligned address into buffer @@ -238,92 +265,83 @@ uint16_t sd_align_address(uint32_t * pAddress); * * @return Number of bytes read (should always be = sd_state.BlockLen) */ -uint16_t sd_read_block(void (*const pBuffer), const uint32_t address); + 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 /* */ + /** + * @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 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 result code (see enum #sd_write_ret) + * + * \Note + * Only supported block size for writing is usually 512 bytes. + */ + enum sd_write_ret sd_write_block(const uint32_t address, + void const (*const pBuffer)); -/** - * @brief Flush the DMA write buffer - * - * Wait for a running DMA write operation to finish - */ -uint16_t sd_write_flush(void); + /** + * @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 result code (see enum #sd_write_ret) + * + * @note Use this for settings blocks to 0x00. + * Only supported block size for writing is usually 512 bytes. + */ + enum sd_write_ret 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 + */ + enum sd_write_ret sd_write_flush(void); #endif #if SD_CACHE -#define SD_WAIT_LOCK(x) \ - while( x ->state & SD_CACHE_LOCKED ) { _NOP(); } +#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) -#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); + /** + * @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 /** @@ -334,7 +352,7 @@ sd_cache_t *sd_cache_read_block(const uint32_t * blAdr); * @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); + bool sd_erase_blocks(const uint32_t address, const uint16_t numBlocks); /** * @brief Read card identification register (CID) @@ -343,7 +361,7 @@ bool sd_erase_blocks(const uint32_t address, const uint16_t numBlocks); * * @see ::sd_cid_t */ -uint16_t sd_read_cid(sd_cid_t * pCID); + uint16_t sd_read_cid(struct sd_cid *pCID); /** * @brief Read size of card @@ -351,8 +369,21 @@ uint16_t sd_read_cid(sd_cid_t * pCID); * * Reads the number of bytes in the card memory from the CSD register. */ -uint32_t sd_get_size(void); + uint32_t sd_get_size(void); -#endif /* !SD_H */ +#if SD_READ_ANY + + /** + * @brief Read any number of bytes from any address into buffer + * + * @param[out] pBuffer Pointer to a buffer to which data is read. It should be least + * size bytes large + * @param[in] address The address of the first byte that shall be read to pBuffer + * @param[in] size Number of bytes which shall be read starting at address + */ + uint16_t sd_read(void *pBuffer, uint32_t address, uint16_t size); +#endif + +#endif /*__SD_H__*/ /** @} */ diff --git a/platform/msb430/dev/sd/sd_cache.c b/platform/msb430/dev/sd/sd_cache.c index 519198ae1..f5008a6e2 100644 --- a/platform/msb430/dev/sd/sd_cache.c +++ b/platform/msb430/dev/sd/sd_cache.c @@ -41,68 +41,101 @@ scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). Berlin, 2007 */ + /** - * @file ScatterWeb.sd.cache.c + * @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 + * @version $Revision: 1.2 $ + * + * $Id: sd_cache.c,v 1.2 2008/03/28 15:58:43 nvt-se Exp $ */ + /** * @addtogroup libsd * @{ */ #include "sd_internals.h" -#include "sd.h" #if SD_CACHE + void -sd_cache_init(void) +_sd_cache_init() { + 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) +_sd_cache_flush() { + #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 + +#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 false; + } + } + return sd_state.Cache; + } @@ -110,65 +143,97 @@ sd_cache_read_block(const uint32_t * pblAdr) 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; + p = (char *)pBuffer; + bytes_left = size; // align to block - offset = sd_align_address(&address); + offset = sd_AlignAddress(&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; + p = (char *)pBuffer; + bytes_left = size; // align to block - offset = sd_align_address(&address); + offset = sd_AlignAddress(&address); + + sd_set_blocklength(SD_WRITE_BLOCKLENGTH_BIT); // @@ -178,25 +243,49 @@ sd_write(uint32_t address, void *pBuffer, uint16_t size) // 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_state.Cache->state |= SD_CACHE_DIRTY; + + 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); + } @@ -204,4 +293,5 @@ sd_write(uint32_t address, void *pBuffer, uint16_t size) #endif // SD_CACHE + /** @} */ diff --git a/platform/msb430/dev/sd/sd_erase.c b/platform/msb430/dev/sd/sd_erase.c index a8d9020d2..732f38fc6 100644 --- a/platform/msb430/dev/sd/sd_erase.c +++ b/platform/msb430/dev/sd/sd_erase.c @@ -41,16 +41,19 @@ scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). Berlin, 2007 */ + /** - * @file ScatterWeb.sd.erase.c + * @file ScatterWeb.Sd.erase.c * @ingroup libsd * @brief MMC-/SD-Card library, Block erase * * @author Michael Baar - * @date Feb 2007 - * @version 0.2 + * @version $Revision: 1.2 $ + * + * $Id: sd_erase.c,v 1.2 2008/03/28 15:58:44 nvt-se Exp $ */ + /** * @addtogroup libsd * @{ @@ -64,21 +67,26 @@ sd_erase_blocks(uint32_t address, uint16_t numBlocks) uint8_t ret, r1; uint32_t endAdr; - if (sd_protected()) + 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) + } + + ret = _sd_send_cmd(SD_CMD_ERASE_WR_BLK_START_ADDR, SD_RESPONSE_SIZE_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) + + ret = _sd_send_cmd(SD_CMD_ERASE_WR_BLK_END_ADDR, SD_RESPONSE_SIZE_R1, + &endAdr, &r1); + if (!ret | r1) { return FALSE; - ret = sd_send_cmd(SD_CMD_ERASE, SD_RESPONSE_TYPE_R1, NULL, &r1); + } + + ret = _sd_send_cmd(SD_CMD_ERASE, SD_RESPONSE_SIZE_R1, NULL, &r1); return ret; } diff --git a/platform/msb430/dev/sd/sd_info.c b/platform/msb430/dev/sd/sd_info.c index 2e9a4edec..327b43297 100644 --- a/platform/msb430/dev/sd/sd_info.c +++ b/platform/msb430/dev/sd/sd_info.c @@ -41,16 +41,19 @@ scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). Berlin, 2007 */ + /** - * @file ScatterWeb.sd.info.c + * @file ScatterWeb.Sd.info.c * @ingroup libsd * @brief MMC-/SD-Card library, Additional Information * * @author Michael Baar - * @date Feb 2007 - * @version 0.2 + * @version $Revision: 1.2 $ + * + * $Id: sd_info.c,v 1.2 2008/03/28 15:58:44 nvt-se Exp $ */ + /** * @addtogroup libsd * @{ @@ -58,29 +61,48 @@ Berlin, 2007 #include "sd_internals.h" #include "sd.h" -uint16_t -sd_read_cid(sd_cid_t * pCID) +unsigned int +sd_read_cid(struct sd_cid *pCID) { - return sd_read_register(pCID, SD_CMD_SEND_CID, sizeof (sd_cid_t)); + + return _sd_read_register(pCID, SD_CMD_SEND_CID, sizeof (struct sd_cid)); + } unsigned long -sd_get_size(void) + +sd_get_size() { + 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))) { + if (uart_lock(UART_MODE_SPI)) { + + struct sd_csd csd; + + + if (_sd_read_register(&csd, SD_CMD_SEND_CSD, sizeof (struct sd_csd))) { + 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 index ae82eb70e..569c05005 100644 --- a/platform/msb430/dev/sd/sd_internals.h +++ b/platform/msb430/dev/sd/sd_internals.h @@ -42,31 +42,30 @@ Berlin, 2007 */ /** - * @file ScatterWeb.sd.internals.h + * @file ScatterWeb.Sd.internals.h * @ingroup libsd * @brief MMC-/SD-Card library * * @author Michael Baar - * @date Jan 2007 - * @version 0.2 + * @version $Revision: 1.2 $ * * Header file containing private declarations used MMC-/SD-Card library. + * + * $Id: sd_internals.h,v 1.2 2008/03/28 15:58:44 nvt-se Exp $ */ -#ifndef SD_INTERNALS_H -#define SD_INTERNALS_H +#ifndef SD_INT_H_ +#define SD_INT_H_ #include -#include "contiki-msb430.h" +#include "sd_platform.h" -#define RETF(x) if( ! x ) return false; -#define MIN(x, y) ( x < y ) ? x : y +#define RETF(x) if( ! x ) return FALSE; /** * @name SD Card SPI responses */ - -struct sd_response_r1_bits { +struct sd_response_r1 { uint8_t in_idle_state:1; uint8_t erase_reset:1; uint8_t illegal_cmd:1; @@ -77,17 +76,41 @@ struct sd_response_r1_bits { 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_response_r2 { + uint16_t in_idle_state:1; + uint16_t erase_reset:1; + uint16_t illegal_cmd:1; + uint16_t crc_err:1; + uint16_t erase_seq_err:1; + uint16_t address_err:1; + uint16_t param_err:1; + uint16_t start_bit:1; + + uint16_t card_locked:1; + uint16_t write_failed:1; + uint16_t unspecified_err:1; + uint16_t controller_err:1; + uint16_t ecc_failed:1; + uint16_t protect_violation:1; + uint16_t erase_param:1; + uint16_t out_of_range:1; }; +#ifdef __TI_COMPILER_VERSION__ +#pragma pack(1) +#endif +struct sd_response_r3 { + struct sd_response_r1 r1; +#ifdef __GNUC__ + __attribute__ ((packed)) +#endif + uint32_t ocr; +}; + +#ifdef __TI_COMPILER_VERSION__ +#pragma pack() +#endif + struct sd_read_error_token { uint8_t unspecified_err:1; uint8_t controller_err:1; @@ -102,132 +125,112 @@ struct sd_data_error_token { 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) + 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 +#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 +int _sd_reset(struct sd_response_r3 *pOpCond); -// Reset card -bool sd_reset(void); +/// Send command and read response +bool _sd_send_cmd(const uint8_t command, + const int response_size, + const void *pArg, void (*const pResponse) + ); -// Send command and read response -bool sd_send_cmd(const uint8_t command, const uint8_t response_type, - const void *pArg, void (*const pResponse)); +/// Wait for card to leave idle mode +bool _sd_wait_standby(struct sd_response_r3 *pOpCond); -// Select card -void sd_select(void); +/// Read card register +uint16_t _sd_read_register(void (*const pBuffer), const uint8_t cmd, + const uint16_t size); -// Unselect card -void sd_unselect(void); +/// Begin block read operation +bool _sd_read_start(const uint8_t cmd, const uint32_t address); -// 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); +/// 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 /* */ +enum sd_write_ret _sd_write_block(const uint32_t * pAddress, + const void *pBuffer, int increment); +#endif #if SD_CACHE -void sd_cache_init(void); -void sd_cache_flush(void); - -#endif /* */ +void _sd_cache_init(); +void _sd_cache_flush(); +#endif ///@} -#define SD_TOKEN_READ 0xFE -#define SD_TOKEN_WRITE 0xFE -#define SD_TOKEN_ZP 0xFF +#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_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_RESET_RETRY_COUNT 4 -#define SD_V_MASK 0x003E0000 // 3,4 - 2,9 V +#define SD_OCR_BUSY(ocr) ((ocr & 0x80000000) == 0) +#define SD_V_MASK 0x003E0000 // 3,4 - 2,9 V +#define SD_HCR_BIT 0x40000000 -#define SD_RESPONSE_TYPE_R1 1 -#define SD_RESPONSE_TYPE_R2 2 -#define SD_RESPONSE_TYPE_R3 5 +#define SD_RESPONSE_SIZE_R1 1 +#define SD_RESPONSE_SIZE_R2 2 +#define SD_RESPONSE_SIZE_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 +#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 /* */ + 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 /* */ + 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_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 -#define SD_ACMD_SEND_OP_COND 41 // R1 +#define SD_ACMD_SEND_OP_COND 41 // R1 //@} -#endif /* !SD_INTERNALS_H */ +#endif /*SD_INT_H_ */ diff --git a/platform/msb430/dev/sd/sd_msb430.c b/platform/msb430/dev/sd/sd_msb430.c new file mode 100644 index 000000000..a78473a50 --- /dev/null +++ b/platform/msb430/dev/sd/sd_msb430.c @@ -0,0 +1,92 @@ + +/* +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.MSB430.c + * @ingroup libsd + * @brief MMC-/SD-Card library initialisation for MSB430 + * + * @author Michael Baar + * @date Jan 2007 + * @version $Revision: 1.1 $ + * + * Replace this file for use on another platform. + * + * $Id: sd_msb430.c,v 1.1 2008/03/28 15:58:44 nvt-se Exp $ + */ + +#include "sd_internals.h" + +void +sd_init_platform(void) +{ + sdspi_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 +} + +/** + * @brief Activate SD Card on SPI Bus + * \internal + */ +__inline void +sdspi_select() +{ + P5OUT &= ~0x01; // Card Select +} + +__inline void +sdspi_unselect() +{ + UART_WAIT_TXDONE(); + + P5OUT |= 0x01; // Card Deselect + sdspi_tx(0xFF); +} diff --git a/platform/msb430/dev/sd/sd_platform.h b/platform/msb430/dev/sd/sd_platform.h new file mode 100644 index 000000000..4c898df13 --- /dev/null +++ b/platform/msb430/dev/sd/sd_platform.h @@ -0,0 +1,65 @@ + +/* +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.Platform.h + * @ingroup libsd + * @brief MMC-/SD-Card library initialisation for MSB430 + * + * @author Michael Baar + * @date Jan 2007 + * @version $Revision: 1.1 $ + * + * Replace this file for use on another platform. + * + * $Id: sd_platform.h,v 1.1 2008/03/28 15:58:44 nvt-se Exp $ + */ + +#ifndef __SCATTERWEB_SD_PLATFORM__ +#define __SCATTERWEB_SD_PLATFORM__ + +#include +#include "contiki.h" +#include "dev/msb430-uart1.h" + +#endif diff --git a/platform/msb430/dev/sd/sdspi.c b/platform/msb430/dev/sd/sdspi.c new file mode 100644 index 000000000..e3dfaf03e --- /dev/null +++ b/platform/msb430/dev/sd/sdspi.c @@ -0,0 +1,226 @@ + +/* +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.Spi.c + * @ingroup libsdspi + * @brief Serial Peripheral Interface for SD library + * + * @author Michael Baar + * @version $Revision: 1.1 $ + * + * $Id: sdspi.c,v 1.1 2008/03/28 15:58:44 nvt-se Exp $ + */ + +#include +#include "contiki-msb430.h" + +#if SPI_DMA_WRITE +uint8_t sdspi_dma_lock; +#endif + +#ifndef U1IFG +#define U1IFG IFG2 +#endif + +#define SPI_IDLE_SYMBOL 0xFF + +void +sdspi_init(void) +{ +#if SPI_DMA_WRITE + sdspi_dma_lock = FALSE; +#endif + + /* The 16-bit value of UxBR0+UxBR1 is the division factor of the USART clock + * source, BRCLK. The maximum baud rate that can be generated in master + * mode is BRCLK/2. The maximum baud rate that can be generated in slave + * mode is BRCLK. The modulator in the USART baud rate generator is not used + * for SPI mode and is recommended to be set to 000h. The UCLK frequency is + * given by: + * Baud rate = BRCLK / UxBR with UxBR= [UxBR1, UxBR0] + */ + uart_set_speed(UART_MODE_SPI, 0x02, 0x00, 0x00); +} + +uint8_t +sdspi_rx(void) +{ + UART_TX = SPI_IDLE_SYMBOL; + UART_WAIT_RX(); + return (UART_RX); +} + +void +sdspi_tx(register const uint8_t c) +{ + UART_TX = c; + UART_WAIT_TXDONE(); +} + +#if SPI_DMA_READ || SPI_DMA_WRITE +void +sdspi_dma_wait(void) +{ + while (DMA0CTL & DMAEN) { + _NOP(); + } // Wait until a previous transfer is complete +} +#endif + +void +sdspi_read(void *pDestination, const uint16_t size, const bool incDest) +{ +#if SPI_DMA_READ + sdspi_dma_wait(); + + UART_RESET_RXTX(); // clear interrupts + + // Configure the DMA transfer + DMA0SA = (uint16_t) & UART_RX; // source DMA address + DMA0DA = (uint16_t) pDestination; // destination DMA address + DMA0SZ = size; // number of bytes to be transferred + DMA1SA = (uint16_t) & UART_TX; // source DMA address (constant 0xff) + DMA1DA = DMA1SA; // destination DMA address + DMA1SZ = size - 1; // number of bytes to be transferred + DMACTL0 = DMA0TSEL_9 | DMA1TSEL_9; // trigger is UART1 receive for both DMA0 and DMA1 + DMA0CTL = DMADT_0 | // Single transfer mode + DMASBDB | // Byte mode + DMADSTINCR0 | DMADSTINCR1 | // Increment destination + DMAEN; // Enable DMA + if (!incDest) { + DMA0CTL &= ~(DMADSTINCR0 | DMADSTINCR1); + } + + DMA1CTL = DMADT_0 | // Single transfer mode + DMASBDB | // Byte mode + DMAEN; // Enable DMA + + UART_TX = SPI_IDLE_SYMBOL; // Initiate transfer by sending the first byte + sdspi_dma_wait(); + +#else + register uint8_t *p = (uint8_t *) pDestination; + register uint16_t i = size; + + do { + UART_TX = SPI_IDLE_SYMBOL; + UART_WAIT_RX(); + *p = UART_RX; + if (incDest) { + p++; + } + i--; + } while (i); +#endif +} + +#if SPI_WRITE +void +sdspi_write(const void *pSource, const uint16_t size, const int increment) +{ +#if SPI_DMA_WRITE + sdspi_dma_wait(); + + UART_RESET_RXTX(); // clear interrupts + + // Configure the DMA transfer + DMA0SA = ((uint16_t) pSource) + 1; // source DMA address + DMA0DA = (uint16_t) & UART_TX; // destination DMA address + DMA0SZ = size - 1; // number of bytes to be transferred + DMACTL0 = DMA0TSEL_9; // trigger is UART1 receive + DMA0CTL = DMADT_0 | // Single transfer mode + DMASBDB | // Byte mode + DMASRCINCR_3 | // Increment source + DMAEN; // Enable DMA + if (increment == 0) { + DMA0CTL &= ~DMASRCINCR_3; + } + + sdspi_dma_lock = TRUE; + SPI_TX = ((uint8_t *) pSource)[0]; +#else + register uint8_t *p = (uint8_t *) pSource; + register uint16_t i = size; + + do { + UART_TX = *p; + UART_WAIT_TXDONE(); + UART_RX; + p += increment; + i--; + } while (i); +#endif +} +#endif + +void +sdspi_idle(register const uint16_t clocks) +{ + register uint16_t i = clocks; + + do { + UART_TX = SPI_IDLE_SYMBOL; + UART_WAIT_RX(); + UART_RX; + i--; + } while (i); +} + + +uint16_t +sdspi_wait_token(const uint8_t feed, const uint8_t mask, + const uint8_t token, const uint16_t timeout) +{ + uint16_t i = 0; + uint8_t rx; + + do { + UART_TX = feed; + UART_WAIT_RX(); + rx = UART_RX; + i++; + } while (((rx & mask) != token) && (i < timeout)); + return i; +} diff --git a/platform/msb430/dev/sd/sdspi.h b/platform/msb430/dev/sd/sdspi.h new file mode 100644 index 000000000..9e7417c55 --- /dev/null +++ b/platform/msb430/dev/sd/sdspi.h @@ -0,0 +1,143 @@ + +/* +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 +*/ + +/** + * @addtogroup uart1 + * @ingroup libsd_spi + * @{ + */ + +/** + * @file ScatterWeb.Spi.h + * @ingroup libsdspi + * @brief Serial Peripheral Interface + * + * @author Michael Baar + * @version $Revision: 1.1 $ + * + * $Id: sdspi.h,v 1.1 2008/03/28 15:58:44 nvt-se Exp $ + */ + +#ifndef __SPI_H__ +#define __SPI_H__ + +#ifndef SPI_DMA_READ +#define SPI_DMA_READ 0 +#endif +#ifndef SPI_DMA_WRITE +#define SPI_DMA_WRITE 0 +#endif +#ifndef SPI_WRITE +#define SPI_WRITE 1 +#endif + +/** + * @brief Init SPI driver + */ +void sdspi_init(void); + +/// chipselect +__inline void sdspi_select(); +__inline void sdspi_unselect(); + +/** + * @brief Receive one byte from SPI + */ +uint8_t sdspi_rx(void); + +/** + * @brief Send one byte to SPI + * + * @param[in] c Byte to send + */ +void sdspi_tx(const uint8_t c); + +/** + * @brief Read a number of bytes from SPI + * + * @param[in] pDestination Pointer to buffer to store bytestream + * @param[in] size Number of bytes to store in pDestination + * @param[in] incDest Increment destination pointer after each byte by one (or not) + */ +void sdspi_read(void *pDestination, const uint16_t size, const bool incDest); + +#if SPI_DMA_WRITE +extern uint8_t sdspi_dma_lock; +#endif +#if SPI_DMA_READ || SPI_DMA_WRITE +void sdspi_dma_wait(void); +#endif + +#if SPI_WRITE + /** + * @brief Write a number of bytes to SPI + * + * @param[in] pSource Pointer to buffer with data to send + * @param[in] size Number of bytes to send + * @param[in] startToken First byte to send before starting to send size bytes from pSource + * @param[in] incSource Increment source pointer after each byte by one (or not) + */ +void sdspi_write(const void *pSource, + const uint16_t size, const int increment); +#endif + +/** + * @brief Wait a number of clock cycles + * + * @param[in] clocks Wait clocks x 8 cycles + */ +void sdspi_idle(const uint16_t clocks); + +/** + * @brief Read bytes from SPI until token is received + * + * @param[in] token Token to wait for + * @param[in] timeout Maximum number of bytes to read + * @return true if token received, false otherwise + */ +uint16_t sdspi_wait_token(const uint8_t feed, const uint8_t mask, + const uint8_t token, const uint16_t timeout); + +#endif /*__SPI_H__*/ + +/** @} */