HI,
I've taken the example code slaa281b and I'm not getting a response from two microSD cards (I've tried with the MSP-EXP430F5529LP
I've connected the microSD as follows
microSD MSP430
Pin1(NC) N/A
Pin2(CS) <----------------------- P3.4(GPIO)
Pin3(DI) <----------------------- P3.0(SIMO)
Pin4(Vdd) <---------------------- 3V3
Pin5(CLK) <---------------------- P3.2(SCLK)
Pin6(Vss) <---------------------- GND
Pin7(DO) ----------------------> P3.1(SOMI)
Pin8(NC) N/A
A 47K resistor is on the CS line to 3V3, a 100nF cap is between 3V3 and GND and the code has been tried with and without a 10K resistor tried high on DO.
I have a scope on all four pins (also tested on pads of microSD card), the CLK is at 200kHz and the other pins are responding as in the code and yet no output is seen on DO.
-With the DO tied high, it remains high throughout the initialisation and GO_IDLE_STATE command
-With the pull up removed DO remains low throughout the initialisation and GO_IDLE_STATE command
Here is my complete code
#include <msp430.h> #include <stdio.h> #define TRUE 1 #define FALSE 0 unsigned int clkFail = 0; unsigned int XT2Fail = 0; #define SD_CS BIT4 #define SD_DETECT BIT5 #define SD_SIMO BIT0 #define SD_SOMI BIT1 #define SD_CLK BIT2 #define CS_LOW() P3OUT &= ~SD_CS // Card Select #define CS_HIGH() while (!(UCB0IFG&UCTXIFG)); P3OUT |= SD_CS // Card Deselect unsigned char microSD; unsigned char mircoSDError; #define SD_SUCCESS 0x00 #define SD_BLOCK_SET_ERROR 0x01 #define SD_RESPONSE_ERROR 0x02 #define SD_DATA_TOKEN_ERROR 0x03 #define SD_INIT_ERROR 0x04 #define SD_CRC_ERROR 0x10 #define SD_WRITE_ERROR 0x11 #define SD_OTHER_ERROR 0x12 #define SD_TIMEOUT_ERROR 0xFF #define DUMMY_CHAR 0xFF #define SD_GO_IDLE_STATE 0x40 //CMD0 #define SD_SEND_OP_COND 0x41 //CMD1 #define CMD0_CRC 0x95 static void _UCSinitDev(void); void SetVcoreUp (unsigned int level); void _SDinit (void); char SDidle (void); void SDSendCmd (const char cmd, unsigned long data, const char crc); char SDGetResponse(void); unsigned char SDSendFrame(unsigned char* pBuffer, unsigned int size); char SDPing(void); int main(void) { WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer _UCSinitDev(); // Setup UCS __enable_interrupt(); _SDinit (); } /*************/ /* UCS setup */ /*************/ static void _UCSinitDev(void) { static unsigned int clkRetries,XT2Retries = 0; static const unsigned int CLK_RETRIES_MAX = 0xFFFF; P5SEL |= (BIT2 | BIT3); // Set P5.2/3 to XT2 P1SEL |= BIT0; P1DIR |= BIT0; SetVcoreUp (0x01); SetVcoreUp (0x02); SetVcoreUp (0x03); UCSCTL6 |=(XT1OFF); // Turn Off XT1 UCSCTL6 &=~(XT2OFF); // Enable XT2 UCSCTL6 |= (XT2DRIVE_3); // Loop until XT1 fault flag is cleared do { UCSCTL7 &= ~XT2OFFG; // Clear XT1 fault flags XT2Retries++; } while ((UCSCTL7&XT2OFFG) && (XT2Retries < CLK_RETRIES_MAX)); // Test XT1 fault flag if(XT2Retries == 0xFFFE) { XT2Fail = 1; } //XT2 now stable, reduce drive strength UCSCTL6 |= (XT2DRIVE_2); UCSCTL3 = (SELREF__XT2CLK | FLLREFDIV__16); // DCO_Ref = XT2/16 // -> 4MHz/16 = 0.25 MHz __bis_SR_register(SCG0); // Disable the FLL control loop UCSCTL1 = (DCORSEL_5); // Set DCORSEL to 5 UCSCTL2 = (0x001F | FLLD__16); // DCOCLK = DCO_Ref x (31+1) x FLLD__#, DCOCLKDIV = DCOCLK / FLLD__# // -> DCOCLK = 16 MHz, DCOCLKDIV = 1 MHz __bis_SR_register(SCG0); // Enable the FLL control loop UCSCTL4 = (SELA__DCOCLKDIV | SELS__DCOCLK | SELM__DCOCLK); // ACLK = DCOCLK, SMCLK = MCLK = DCOCLK UCSCTL5 = (DIVPA__1 | DIVA__1 | DIVS__1 | DIVM__1); // Output pin clk = ACLK/16 = 1 MHz __delay_cycles(253952); do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags clkRetries++; } while ((SFRIFG1&OFIFG) && (clkRetries < CLK_RETRIES_MAX)); // Test oscillator fault flag if(clkRetries == 0xFFFE) { clkFail = 1; } } void SetVcoreUp (unsigned int level) { // Open PMM registers for write PMMCTL0_H = PMMPW_H; // Set SVS/SVM high side new level SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level; // Set SVM low side to new level SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level; // Wait till SVM is settled while ((PMMIFG & SVSMLDLYIFG) == 0); // Clear already set flags PMMIFG &= ~(SVMLVLRIFG + SVMLIFG); // Set VCore to new level PMMCTL0_L = PMMCOREV0 * level; // Wait till new level reached if ((PMMIFG & SVMLIFG)) while ((PMMIFG & SVMLVLRIFG) == 0); // Set SVS/SVM low side to new level SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Lock PMM registers for write access PMMCTL0_H = 0x00; } /*************/ /* microSD */ /*************/ void _SDinit (void) { int i; unsigned char SDstatus = FALSE; int timeout; unsigned char response; if (!SDPing()) // No microSD card { microSD = FALSE; } else // microSD card is inserted { while (SDstatus != TRUE) // SD not initialised { // Init Port for SD (default high) P3OUT |= SD_SIMO + SD_CLK; P3DIR |= SD_SIMO + SD_CLK; // Chip Select P3OUT |= SD_CS; P3DIR |= SD_CS; // Init SPI Module // UCB0CTL1 |= UCSWRST; // **Put state machine in reset** UCB0CTL0 = UCMST+UCCKPL+UCMSB+UCSYNC; // 3-pin, 8-bit SPI master UCB0CTL1 = UCSSEL__ACLK + UCSWRST; // **Put state machine in reset** // UCB0CTL1 |= UCSSEL__ACLK; // ACLK UCB0BR0 |= 0x05; // SPICLK = 400kHz UCB0BR1 = 0; // P3SEL |= SD_SIMO + SD_SOMI + SD_CLK; // Enable SIMO, SOMI and SCLK pins UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** // Initialization sequence on PowerUp CS_HIGH(); for(i=0;i<=20;i++) { spiSendByte(DUMMY_CHAR); } SDstatus = SDidle(); timeout++; if (timeout == 150) // Try 150 times till error { microSD = FALSE; return; } } microSD = TRUE; } } char SDidle (void) { char response=0x01; CS_LOW(); //Send Command 0 to put MMC in SPI mode SDSendCmd(SD_GO_IDLE_STATE,0,CMD0_CRC); //Now wait for READY RESPONSE if(SDGetResponse()!=0x01) { mircoSDError = SD_INIT_ERROR; return (FALSE); } while(response==0x01) { CS_HIGH(); spiSendByte(DUMMY_CHAR); // Send single Byte on SPI CS_LOW(); SDSendCmd(SD_SEND_OP_COND,0x00,0xFF); response = SDGetResponse(); } CS_HIGH(); spiSendByte(DUMMY_CHAR); return (TRUE); } //Send one byte via SPI unsigned char spiSendByte(const unsigned char data) { while (!(UCB0IFG&UCTXIFG)); // wait while not ready for TX UCB0TXBUF = data; // write while (!(UCB0IFG&UCRXIFG)); // wait for RX buffer (full) return (UCB0RXBUF); } void SDSendCmd (const char cmd, unsigned long data, const char crc) { unsigned char frame[6]; char temp; int i; frame[0]=(cmd|0x40); for(i=3;i>=0;i--) { temp = (char)(data>>(8*i)); frame[4-i] = (temp); } frame[5]=(crc); SDSendFrame(frame,6); } char SDGetResponse(void) { //Response comes 1-8bytes after command //the first bit will be a 0 //followed by an error code //data will be 0xff until response int i=0; char response; while(i<=64) { response = spiSendByte(DUMMY_CHAR); if(response==0x00)break; if(response==0x01)break; i++; } return response; } unsigned char SDSendFrame(unsigned char* pBuffer, unsigned int size) { unsigned long i = 0; // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block for (i = 0; i < size; i++) { while (!(UCB0IFG&UCTXIFG)); // USCI_B0 TX buffer ready? UCB0TXBUF = (0xFF); // LSB not transfer buffer while (!(UCB0IFG&UCRXIFG)); // USCI_B0 RX buffer full? pBuffer[i] = UCB0RXBUF; } return(0); } char SDPing(void) { /* // Card Detect P3DIR &= ~SD_DETECT; if (!(P3IN & SD_DETECT)) //SD_DETECT Pulled Low { return (TRUE); } else //SD_DETECT Pulled High { return (FALSE); } */ return (TRUE); }