I'm struggling with code to talk with a MultiMedia Card using SPI. I can generally read the card, though not always. It SEEMS that if I put in more inits (command 1), it works better. Sometimes the init returns a result of 1 instead of 0. Trying it again may return a 0, and the read seems to work then (but I'm not sure). When the read doesn't work, I get the 0 response, then can wait for ever for the FE start of data. So, MMC experts, I'm hoping you find something obvious wrong with the code below!!! The MMC is running on 3.3V and the PIC is an 18F6720. The compiler is Microchip's MCC18. I've watching SS, CLK, MISO, and MOSI on a Tek TDS3012 scope and stuff generally seems to be happening as I expect (except often on the MOSI side where the MMC does not send the replies I expect). I'm hoping someone can see something obvious I've overlooked! THANKS! Harold ===================code start=================== // mmc.c // Code to talk with the MultiMedia Card used as a personality module. #include #include // SPI commands #include "MmcBuf.h" // The buffers for Mmc #include "serial.h" // serial I/O for test #include // Function Prototypes unsigned char MmcInit(void); // Initialize the card. Returns 0x00 if ok unsigned char MmcReset(void); // Command 0. Initialize the MMC. Returns 0x01 if ok unsigned char MmcReadCid(void); // Command 10. Reads the Card Identification register and returns it in MmcBufLo. unsigned char MmcReadByte(void); // Reads a byte off SPI while sending 0xff unsigned char MmcReadBlock(unsigned long); // Read a block of 512 bytes from specified address unsigned char MmcWriteBlock(unsigned long); // Write a block of 512 bytes at specified address unsigned char MmcSetBlockLength(void); // Set block length to 512 bytes // Defines // Slave Select for MMC #define MmcSS LATEbits.LATE7 #define MmcMisoEnable LATFbits.LATF6 #define MOSI LATCbits.LATC5 #define SpiClk LATCbits.LATC3 #define MISO PORTCbits.RC4 #define Delay10us Delay100TCYx(4) #define Delay1us Delay10TCYx(4) // Functions unsigned char MmcSendByte(unsigned char TxByte){ unsigned char i, RxByte; Delay10us; RxByte=0; // Start with all bits cleared. We'll shift in from right end for(i=0; i<8; i++){ SpiClk=0; if (MISO) RxByte=(RxByte | 0x01); // Set lsb of RxByte if MISO from MMC is high, otherwise it's left low else RxByte=(RxByte | 0x00); // Not needed, but put in so we can break on debug if (TxByte & 0x80) MOSI=1; // Make MOSI reflect msb of data to be transmitted else MOSI=0; Delay10us; SpiClk=1; // Clock high causing MMC to capture data and output next bit Delay10us; // Let Mmc output data stabalize if (i<7) RxByte=RxByte<<1; // Shift RxByte left one for next, but don't shift after last bit brought in TxByte=TxByte<<1; // Shift the TxByte so we send the next lsb next. } // end for MISO=1; // Leave high between bytes Delay10us; return(RxByte); // Return stuff we shifted in } // end function unsigned char MmcReset(void){ // Command 0. Initialize the MMC. Returns 0x01 if ok unsigned char response; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC for(count=0;count<10;count++) MmcSendByte(0xff); // Send at least 74 clocks with MOSI high prior to -SS low MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x40); // Send init sequence MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x95); count=0xff; response=0xff; while((count--) && (response==0xff)) response=MmcSendByte(0xff); // Loop 'til response from mmc MmcSS=1; // Drive -SS on MMC high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus return(response); } unsigned char MmcInit(void){ // Command 1. Initialize the MMC. Returns 0x00 if ok unsigned char response; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x41); // Send command 1 MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0xff); count=0xff; response=0xff; while((count--) && (response==0xff)) // Loop 'til response from mmc response=MmcSendByte(0xff); // Read back a byte MmcSS=1; // Drive -SS on MMC high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus return(response); } unsigned char MmcReadCid(void){ // Command 10. Reads the Card Identification register and returns it in MmcBufLo. Response code is returned. unsigned char response; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x4a); // Send command 10 MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0xff); count=0xff; response=0xff; while((count--) && (response==0xff)) // Loop 'til we get a response from mmc response=MmcSendByte(0xff); // Get a byte while((count--) && (MmcSendByte(0xff)!=0xfe)); // wait for start byte MmcBufLo[0] = MmcSendByte(0xff); // Get the manufacturer's ID MmcBufLo[1] = MmcSendByte(0xff); MmcBufLo[2] = MmcSendByte(0xff); // Get the OEM ID MmcBufLo[3] = MmcSendByte(0xff); // Get first character of the product name MmcBufLo[4] = MmcSendByte(0xff); MmcBufLo[5] = MmcSendByte(0xff); MmcBufLo[6] = MmcSendByte(0xff); MmcBufLo[7] = MmcSendByte(0xff); MmcBufLo[8] = MmcSendByte(0xff); // Last character of product name from MMC MmcBufLo[9] = MmcSendByte(0xff); // Get product revision number MmcBufLo[10]= MmcSendByte(0xff); MmcBufLo[11]= MmcSendByte(0xff); MmcBufLo[12]= MmcSendByte(0xff); MmcBufLo[13]= MmcSendByte(0xff); // Get product serial number MmcBufLo[14]= MmcSendByte(0xff); // Get manufacturer's date code MmcBufLo[15]= MmcSendByte(0xff); // Get CRC MmcBufLo[16]= MmcSendByte(0xff); // Get and throw out first byte of CRC MmcBufLo[17]= MmcSendByte(0xff); // Get and throw out second byte of CRC MmcSS=1; // Set slave select high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus return(response); // return error code } unsigned int SendStatus(void){ // Command 13. Return status word unsigned char count, responseLo, responseHi; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x40+13); // Send command 13 MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0xff); count=0xff; responseHi=0xff; while((count--) && (responseHi==0xff)) // Loop 'til we get a response from mmc responseHi=MmcSendByte(0xff); // Get a byte responseLo=MmcSendByte(0xff); // Get the low byte of the response MmcSendByte(0xff); // Get and throw out first byte of CRC MmcSendByte(0xff); // Get and throw out second byte of CRC MmcSS=1; // Set slave select high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus return((unsigned int)responseLo + (unsigned int)responseHi<<8); // return status word } unsigned char MmcSetBlockLength(void){ // Set block length to 512 bytes unsigned char response; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x50); // Send command MmcSendByte(0x00); MmcSendByte(0x00); MmcSendByte(0x01); // High half of length (512) MmcSendByte(0x00); MmcSendByte(0xff); // fake crc count=0xff; response=0xff; while((count--) && (response==0xff)) // Loop 'til response from mmc response=MmcSendByte(0xff); // Read back a byte MmcSS=1; // Drive -SS on MMC high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus return(response); } unsigned char MmcReadBlock(unsigned long addr){ // Reads 512 bytes from mmc starting at addr. Store first 256 bytes in MmcBufLo and second // 256 bytes in MmcBufHi. unsigned char response; unsigned int index; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x51); // Send command 17 MmcSendByte((unsigned char) (addr >> 24)); // Send msb of address MmcSendByte((unsigned char) (addr >> 16)); // Send address MmcSendByte((unsigned char) (addr >> 8)); // Send address MmcSendByte((unsigned char) (addr)); // Send lsb of address MmcSendByte(0xff); // send fake crc count=0xff; // time out value response=0xff; while((count--) && (response==0xff)) // Wait for response from mmc response=MmcSendByte(0xff); // Read back a byte count=0xff; // time out value while((count--) && (MmcSendByte(0xff)!=0xfe)); // Wait for 0xfe - Loop 'til we read a 0xfe or time out for(index=0; index<256; index++) MmcBufLo[index]=MmcSendByte(0xff); // Read 256 bytes into low buffer for(index=0; index<256; index++) MmcBufHi[index]=MmcSendByte(0xff); // Read 256 bytes into high buffer MmcSendByte(0xff); // Eat first byte of crc MmcSendByte(0xff); // Eat second byte of CRC MmcSS=1; // Set slave select high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus } unsigned char MmcWriteBlock(unsigned long addr){ // Writes 512 bytes to mmc starting at addr from MmcBuf with the first 256 bytes in MmcBufLo and the second // 256 bytes in MmcBufHi. unsigned char response; unsigned int index; unsigned short long count; MmcMisoEnable=0; // Let PIC read MISO from MMC MmcSS=0; // Drive -SS on MMC low MmcSendByte(0x58); // Send write command MmcSendByte((unsigned char) (addr >> 24)); // Send msb of address MmcSendByte((unsigned char) (addr >> 16)); // Send address MmcSendByte((unsigned char) (addr >> 8)); // Send address MmcSendByte((unsigned char) (addr)); // Send lsb of address MmcSendByte(0xff); // send fake crc count=0xff; // time out value response=0xff; while((count--) && (response==0xff)) // Wait for 0x00 -Loop 'til we read a 0 or time out response=MmcSendByte(0xff); // Read back a byte count=0xff; // time out value MmcSendByte(0xff); // Send another 8 clocks after getting 0x00 from MMC MmcSendByte(0xff); // and another 8 for good measure (Nwr=>8) MmcSendByte(0xfe); // Send start of data byte for(index=0; index<256; index++) MmcSendByte(MmcBufLo[index]); // Write 256 bytes from low buffer for(index=0; index<256; index++) MmcSendByte(MmcBufHi[index]); // Write 256 bytes from high buffer MmcSendByte(0xff); // Send fake crc first byte MmcSendByte(0xff); // and second byte count=0xfffff; // time out value while((count--) && (MmcSendByte(0xff)==0x00)); // Wait for 0x00 indicating busy count=0xfff; // time out value while((count--) && (MmcSendByte(0xff)!=0xff)) // Wait for 0xff indicating not busy anymore MmcSS=1; // Set slave select high MmcSendByte(0xff); // Send some extra clocks MmcMisoEnable=1; // Take MMC off PIC MISO bus } void MmcTest(void){ // See if MMC routines work! unsigned long n; int ByteNum; unsigned char ErrorCode; unsigned int StatusWord; ErrorCode=MmcReset(); // StatusWord=SendStatus(); ErrorCode=MmcInit(); ErrorCode=MmcInit(); ErrorCode=MmcInit(); ErrorCode=MmcInit(); // ErrorCode=MmcSetBlockLength(); // Set block length to 512 bytes // StatusWord=SendStatus(); // ErrorCode=MmcReadCid(); // StatusWord=SendStatus(); // ErrorCode=MmcReadBlock(512*89); // memcpypgm2ram(MmcBufLo, "Hello World\n", 13); MmcBufLo[0]='H'; MmcBufLo[1]='e'; MmcBufLo[2]='l'; MmcBufLo[3]='l'; MmcBufLo[4]='o'; MmcBufLo[5]=' '; MmcBufLo[6]='W'; MmcBufLo[7]='o'; MmcBufLo[8]='r'; MmcBufLo[9]='l'; MmcBufLo[10]='d'; MmcBufLo[11]='!'; MmcBufLo[12]='\0'; // ErrorCode=MmcWriteBlock(89*512); // StatusWord=SendStatus(); for(n=0; n<100; n++){ // dos data starts at block 89 ErrorCode=MmcReadBlock(512*n); StatusWord=SendStatus(); for(ByteNum=0; ByteNum<256; ByteNum++){ Put32Hex(512*n+ByteNum); // Output the address hputcUSART('\t'); // tab over PutHex(MmcBufLo[ByteNum]); // output hex contents hputcUSART('\t'); // tab over if (MmcBufLo[ByteNum]>0x20) hputcUSART(MmcBufLo[ByteNum]); crlf(); } for(ByteNum=0; ByteNum<256; ByteNum++){ Put32Hex(512*n+ByteNum+256); // Output the address hputcUSART('\t'); // tab over PutHex(MmcBufHi[ByteNum]); // output hex contents hputcUSART('\t'); // tab over if (MmcBufHi[ByteNum]>0x20) hputcUSART(MmcBufHi[ByteNum]); crlf(); } } } ===================code end==================== FCC Rules Online at http://hallikainen.com/FccRules Lighting control for theatre and television at http://www.dovesystems.com Reach broadcasters, engineers, manufacturers, compliance labs, and attorneys. Advertise at http://www.hallikainen.com/FccRules/ . ________________________________________________________________ Sign Up for Juno Platinum Internet Access Today Only $9.95 per month! Visit www.juno.com -- http://www.piclist.com hint: The PICList is archived three different ways. See http://www.piclist.com/#archives for details.