From: ayer1 Date: Fri, 4 Sep 2009 18:15:31 +0000 (+0000) Subject: restored use of tosh_uwait (added back msp430hardware.h) ; it's much X-Git-Tag: rc_6_tinyos_2_1_1~306 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=d4eb8ef3144626da5dbbd993472d359f5054c8a0 restored use of tosh_uwait (added back msp430hardware.h) ; it's much more accurate that busywaitmicro. added in real tos-2 spi transaction code added in updates from tos-1 for handling docking availability, and power-cycling card when switching between sd to spi modes. got rid of auto-init from boot, adding stdcontrol back in. left out .init usage, because tos-1 version had no real functionality in stdcontrol.start, so old stdcontrol.init routine is carried to .start. --- diff --git a/tos/platforms/shimmer/chips/sd/SDP.nc b/tos/platforms/shimmer/chips/sd/SDP.nc index e0eeb9c7..ac9746a5 100644 --- a/tos/platforms/shimmer/chips/sd/SDP.nc +++ b/tos/platforms/shimmer/chips/sd/SDP.nc @@ -3,7 +3,7 @@ * 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 @@ -85,110 +85,158 @@ * * 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; @@ -238,7 +286,7 @@ implementation for(i = 0; i < 65; i++){ response = spiSendByte(0xff); response &= 0x1f; - + switch(response){ case 0x05: rvalue = MMC_SUCCESS; @@ -266,7 +314,7 @@ implementation return response; } - mmcerror_t SD_setIdle() { + error_t setIdle(){ char response; CS_LOW(); @@ -290,8 +338,9 @@ implementation return MMC_SUCCESS; } - mmcerror_t SD_init() { + error_t cardInit(){ register uint8_t i; + uint8_t r; initSPI(); @@ -300,25 +349,25 @@ implementation 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(); } @@ -331,16 +380,19 @@ implementation 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 @@ -348,11 +400,11 @@ implementation 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); @@ -371,20 +423,30 @@ implementation 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); @@ -420,63 +482,48 @@ implementation 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 @@ -487,6 +534,8 @@ implementation 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 @@ -562,4 +611,3 @@ implementation } } -