* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
-* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
+* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
*
* functional pieces based upon or copied from Texas Instruments sample code
*
- */
- /**
- * @author Steve Ayer
- * @author Konrad Lorincz
- * @date March 25, 2008 - ported to TOS 2.x
+ * @author Steve Ayer
+ * @date May 2006
+ * @date July 2009 (extensive rework, tep conformance)
+ * @author Konrad Lorincz (initial port to tos-2)
+ * @date March 25, 2008
*/
#include "SD.h"
+#include "msp430usart.h"
-module SDP
-{
- provides interface SD;
-
- uses interface Boot;
- uses interface HplMsp430Usart;
- uses interface HplMsp430UsartInterrupts;
+module SDP {
+ provides {
+ interface StdControl;
+ interface SD;
+ }
+ uses {
+ interface HplMsp430Usart as Usart;
+ interface HplMsp430Interrupt as DockInterrupt;
+ interface Leds;
+ }
}
-implementation
-{
-#define SPI_TX_DONE while(call HplMsp430Usart.isTxEmpty() == FALSE);
+implementation {
+ error_t cardInit();
+
+#define SPI_TX_DONE while(call Usart.isTxEmpty() == FALSE);
#define CS_LOW() TOSH_CLR_SD_CS_N_PIN(); // Card Select
#define CS_HIGH() SPI_TX_DONE; TOSH_SET_SD_CS_N_PIN();
- async event void HplMsp430UsartInterrupts.txDone() {/*do nothing*/}
- async event void HplMsp430UsartInterrupts.rxDone(uint8_t data) {/*do nothing*/}
+ /*
+ * this routine is supposed to prevent windows from locking up when
+ * the device is docked.
+ */
+ void powerCycle() {
+ // wait until the tx buf is clear before killing the card
+ CS_HIGH();
+ // this connects the path from mcu to card
+ TOSH_MAKE_DOCK_N_OUTPUT();
+ TOSH_SET_DOCK_N_PIN();
- // This is from TOS 1.x!
- void setModeSPI()
- {
- // call USARTControl.disableUART();
- atomic ME1 &= ~(UTXE0 | URXE0); // USART0 UART module enable
- TOSH_SEL_UTXD0_IOFUNC();
- TOSH_SEL_URXD0_IOFUNC();
+ TOSH_SET_SW_SD_PWR_N_PIN();
+ TOSH_CLR_SD_CS_N_PIN();
- //call USARTControl.disableI2C();
- //#ifdef __msp430_have_usart0_with_i2c
- //if (call USARTControl.isI2C())
- atomic U0CTL &= ~(I2C | I2CEN | SYNC);
- //#endif
+ /*
+ * here we have to clear all input pins to the card, as
+ * the card in spi mode will leech power from any pin
+ */
+ call Usart.disableSpi();
+ TOSH_CLR_SD_DI_PIN();
+ TOSH_CLR_SD_DO_PIN();
+ TOSH_CLR_SD_CLK_PIN();
+ TOSH_uwait(20000);
- atomic {
- TOSH_SEL_SIMO0_MODFUNC();
- TOSH_SEL_SOMI0_MODFUNC();
- TOSH_SEL_UCLK0_MODFUNC();
+ TOSH_SET_SD_CS_N_PIN();
+ TOSH_CLR_SW_SD_PWR_N_PIN();
- IE1 &= ~(UTXIE0 | URXIE0); // interrupt disable
+ // undo the override above
+ TOSH_MAKE_DOCK_N_INPUT();
+ }
+
+ command error_t StdControl.start(){
+ TOSH_CLR_SW_SD_PWR_N_PIN(); // powers up module on models so equipped
+
+ /*
+ * this pin, when low, tells us that the sd card is unavailable to the processor
+ * it should be attached to a pullup unless platform has a docking pin doing an sd override;
+ * generally, we need to avoid talking to the sd with the mcu when the pin is low;
+ * if it's low now, we'll fire an interrupt when the sd is available to software.
+ */
+ if(!TOSH_READ_DOCK_N_PIN()){
+ call DockInterrupt.edge(TRUE); // watch for it to go high, off the dock
+ powerCycle();
+ signal SD.unavailable();
+ }
+ else{
+ call DockInterrupt.edge(FALSE); // tell us when we're docked
- U0CTL = SWRST;
- U0CTL |= CHAR | SYNC | MM; // 8-bit char, SPI-mode, USART as master
- U0CTL &= ~(0x20);
+ cardInit();
- U0TCTL = STC ; // 3-pin
- U0TCTL |= CKPH; // half-cycle delayed UCLK
+ signal SD.available();
+ }
- // call USARTControl.setClockSource(SSEL_SMCLK)
- U0TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
- U0TCTL |= (SSEL_SMCLK & 0x7F);
+ call DockInterrupt.enable();
+ call DockInterrupt.clear();
+
+ return SUCCESS;
+ }
- // call USARTControl.setClockRate(UBR_SMCLK_115200, UMCTL_SMCLK_115200);
- // UBR_SMCLK_115200=0x0009, UMCTL_SMCLK_115200=0x10,
- U0BR0 = 0x0009 & 0x0FF;
- U0BR1 = ((0x0009) >> 8) & 0x0FF;
- U0MCTL = 0x10;
+ command error_t StdControl.stop(){
+ TOSH_SET_SW_SD_PWR_N_PIN(); // powers down module
+ TOSH_CLR_SD_CS_N_PIN();
- ME1 &= ~(UTXE0 | URXE0); //USART UART module disable
- ME1 |= USPIE0; // USART SPI module enable
- U0CTL &= ~SWRST;
+ call DockInterrupt.disable();
+ call DockInterrupt.clear();
- IFG1 &= ~(UTXIFG0 | URXIFG0);
- IE1 &= ~(UTXIE0 | URXIE0); // interrupt disabled
+ return SUCCESS;
+ }
+
+ async event void DockInterrupt.fired() {
+ if (call DockInterrupt.getValue() == TRUE){ // off the dock
+ cardInit();
+
+ call DockInterrupt.edge(FALSE);
+ signal SD.available(); // tell the app that it can talk to the sd card
+ }
+ else{
+ call DockInterrupt.edge(TRUE);
+ signal SD.unavailable(); // tell the app to stop talking to the card
+ powerCycle();
}
+ call DockInterrupt.clear();
}
- // setup usart1 in spi mode
void initSPI() {
+ msp430_spi_union_config_t * config;
+
TOSH_MAKE_SD_CS_N_OUTPUT();
TOSH_SEL_SD_CS_N_IOFUNC();
- // call USARTControl.setClockSource(SSEL_SMCLK);
- // call USARTControl.setClockRate(UBR_SMCLK_115200, UMCTL_SMCLK_115200);
- // call USARTControl.setModeSPI();
- setModeSPI(); // the above 3 commands are implemented in this call
+ config = &msp430_spi_default_config;
+
+ call Usart.setModeSpi(config);
+
+ /*
+ * set the clock to 115200 for sd init, default is smclk / 2
+ * cardInit raises speed back to 512k at end of init routine
+ */
+ call Usart.setUbr(UBR_1MHZ_115200);
+ call Usart.setUmctl(UMCTL_1MHZ_115200);
+
+ call Usart.enableRxIntr();
TOSH_SET_SD_CS_N_PIN();
- while(call HplMsp430Usart.isTxEmpty() == FALSE);
+ while(call Usart.isTxEmpty() == FALSE);
}
uint8_t spiSendByte (const uint8_t data){
atomic{
- while(call HplMsp430Usart.isTxEmpty() == FALSE);
-
- call HplMsp430Usart.tx(data);
-
- while(call HplMsp430Usart.isRxIntrPending() == FALSE); // rx buffer has a character
+ while(call Usart.isTxEmpty() == FALSE);
+
+ call Usart.tx(data);
+
+ while(call Usart.isRxIntrPending() == FALSE); // rx buffer has a character
}
- return call HplMsp430Usart.rx();
+ return call Usart.rx();
}
-
+
void sendCmd(const uint8_t cmd, uint32_t data, const uint8_t crc){
uint8_t frame[6];
register int8_t i;
for(i = 0; i < 65; i++){
response = spiSendByte(0xff);
response &= 0x1f;
-
+
switch(response){
case 0x05:
rvalue = MMC_SUCCESS;
return response;
}
- mmcerror_t SD_setIdle() {
+ error_t setIdle(){
char response;
CS_LOW();
return MMC_SUCCESS;
}
- mmcerror_t SD_init() {
+ error_t cardInit(){
register uint8_t i;
+ uint8_t r;
initSPI();
for(i = 0; i < 10; i++)
spiSendByte(0xff);
- return SD_setIdle();
- }
+ r = setIdle();
- event void Boot.booted()
- {
- SD_init();
- }
+ // here's where we set the clock speed up to smclk / 2 (512k)
+
+ call Usart.setUbr(0x0002);
+ call Usart.setUmctl(0x00);
+ return r;
+ }
- // we don't have pin for this one yet; it uses cd pin, which we don't have wired in mock-up
// change block length to 2^len bytes; default is 512
- mmcerror_t SD_setBlockLength (const uint16_t len) {
+ error_t setBlockLength (const uint16_t len) {
CS_LOW ();
sendCmd(MMC_SET_BLOCKLEN, len, 0xff);
// get response from card, should be 0; so, shouldn't this be 'while'?
if(getResponse() != 0x00){
- SD_init();
+ cardInit();
sendCmd(MMC_SET_BLOCKLEN, len, 0xff);
getResponse();
}
return MMC_SUCCESS;
}
-
- // see macro in module for writing to a sector instead of an address
- mmcerror_t SD_readBlock(const uint32_t address, const uint16_t count, uint8_t * buffer){
+ /*
+ * renamed to clear the way for renaming what was readSector -- which called this --
+ * to be renamed readBlock. --sma
+ */
+
+ error_t read_block(const uint32_t address, const uint16_t count, uint8_t * buffer){
register uint16_t i = 0;
uint8_t rvalue = MMC_RESPONSE_ERROR;
-
+
// Set the block length to read
- if(SD_setBlockLength(count) == MMC_SUCCESS){ // block length can be set
+ if(setBlockLength(count) == MMC_SUCCESS){ // block length can be set
CS_LOW ();
-
+
sendCmd(MMC_READ_SINGLE_BLOCK, address, 0xff);
// Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command
// it will do this by sending an affirmative response
if(getResponse() == 0x00){
// now look for the data token to signify the start of the data
if(getXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN){
-
+
// clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block
for (i = 0; i < count; i++)
buffer[i] = spiSendByte(0xff); // is executed with card inserted
-
+
// get CRC bytes (not really needed by us, but required by MMC)
spiSendByte(0xff);
spiSendByte(0xff);
else{
rvalue = MMC_BLOCK_SET_ERROR; // 1
}
-
+
CS_HIGH ();
spiSendByte(0xff);
-
+
return rvalue;
}
- mmcerror_t SD_writeBlock(const uint32_t address, const uint16_t count, uint8_t * buffer){
+ /*
+ * need to test dock pin for some platforms
+ * on others this will be attached to a pullup
+ */
+ command error_t SD.readBlock(const uint32_t sector, uint8_t * buffer) {
+ if(!TOSH_READ_DOCK_N_PIN())
+ return MMC_INIT_ERROR;
+
+ return read_block(sector * 512, 512, buffer);
+ }
+
+ error_t write_block(const uint32_t address, const uint16_t count, uint8_t * buffer){
register uint16_t i;
uint8_t rvalue = MMC_RESPONSE_ERROR; // MMC_SUCCESS;
// Set the block length to write
- if(SD_setBlockLength (count) == MMC_SUCCESS){ // block length could be set
- // call Leds.yellowOn();
+ if(setBlockLength (count) == MMC_SUCCESS){ // block length could be set
CS_LOW ();
sendCmd(MMC_WRITE_BLOCK, address, 0xff);
CS_HIGH ();
// Send 8 Clock pulses of delay.
spiSendByte(0xff);
- // call Leds.greenOn();
- return rvalue;
- }
- command error_t SD.readBlock(const uint32_t sector, void *bufferPtr)
- {
- mmcerror_t mmcerror = SD_readBlock(sector * 512, 512, bufferPtr);
- if (mmcerror == MMC_SUCCESS)
- return SUCCESS;
- else
- return FAIL;
+ return rvalue;
}
+ command error_t SD.writeBlock(const uint32_t sector, uint8_t * buffer){
+ /*
+ * need to test dock pin for some platforms
+ * on others this will be attached to a pullup
+ */
+ if(!TOSH_READ_DOCK_N_PIN())
+ return MMC_INIT_ERROR;
- command error_t SD.writeBlock(const uint32_t sector, void *bufferPtr)
- {
- mmcerror_t mmcerror = SD_writeBlock(sector * 512, 512, bufferPtr);
- if (mmcerror == MMC_SUCCESS)
- return SUCCESS;
- else
- return FAIL;
+ return write_block(sector * 512, 512, buffer);
}
-
- // register read of length len into buffer
- mmcerror_t SD_readRegister(const uint8_t reg, const uint8_t len, uint8_t * buffer){
- uint8_t uc, rvalue = MMC_TIMEOUT_ERROR;
-
- if((SD_setBlockLength (len)) == MMC_SUCCESS){
- CS_LOW ();
- // CRC not used: 0xff as last byte
- sendCmd(reg, 0x000000, 0xff);
-
- // wait for response
- // in the R1 format (0x00 is no errors)
- if(getResponse() == 0x00){
- if(getXXResponse(0xfe) == 0xfe)
- for(uc = 0; uc < len; uc++)
- buffer[uc] = spiSendByte(0xff);
-
- // get CRC bytes (not really needed by us, but required by MMC)
- spiSendByte(0xff);
- spiSendByte(0xff);
- rvalue = MMC_SUCCESS;
+ /*
+ * feel our way out over the cliff of the card to estimate the size
+ * turns out cmd9 is not supported on sdio, as there's no csd register
+ */
+ uint32_t hackGetCardSize() {
+ uint32_t howbig = 0;
+ uint8_t b[512];
+ error_t failed;
+
+ /* we'll estimate based upon popular sizes of cards, e.g. 128mb, 256 mb, 512mb, 1gb, 2gb
+ * experimentally, we find that 512mb == ~990900 sectors, 1gb == ~1983000 sectors
+ * extrapolating down, we'll say that 247700 should be readable on a 128mb
+ * reading beyond that returns an error
+ */
+
+ failed = call SD.readBlock(0, b);
+ failed = call SD.readBlock(200000, b);
+ // if we can't get this far, we're toast anyway
+ if(!failed){
+ howbig = 247000;
+ while(!call SD.readBlock(howbig, b)){
+ howbig = howbig * 2;
}
- else
- rvalue = MMC_RESPONSE_ERROR;
-
- CS_HIGH ();
-
- // Send 8 Clock pulses of delay.
- spiSendByte(0xff);
+ howbig = howbig / 2;
}
- CS_HIGH ();
-
- return rvalue;
- }
+ return howbig;
+ }
// Read the Card Size from the CSD Register
// this command is unsupported on sdio-only, like sandisk micro sd cards
uint16_t i, j, b, response, mmc_C_SIZE;
uint8_t mmc_READ_BL_LEN, mmc_C_SIZE_MULT;
+ // return hackGetCardSize();
+
CS_LOW ();
spiSendByte(MMC_READ_CSD); // CMD 9
}
}
-