'MMC routines adapted from material by Sylvain Bissonette 'SPI routines adapted from material by Tom Handy 'By Anthony Rhodes 2005 Public Const HIGH as Byte = bxOutputHigh Public Const LOW as Byte = bxOutputLow ' Define SPI Port: Public Const MISO As Byte = 27 ' Master-In/Slave-Out on Pin 27 Public Const MOSI As Byte = 26 ' Master-Out/Slave-In on Pin 26 Public Const SCLK As Byte = 25 ' Clock on Pin 25 Public Const SSEL As Byte = 10 ' Slave Select on Pin 10 '************************************************************* '* MMC Init function '* '* - flushes card receive buffer '* - selects card '* - sends the reset command '* - sends the initialization command, waits for card ready '*************************************************************/ Public Function MMCInit() as Integer Dim i as UnsignedInteger Dim j as Byte Dim Dummy as Byte MMCInit = 0 '/* start off with 80 bits of high data with card deselected */ Call PutPin(SSEL, HIGH) 'Deselect the CS pin For I = 1 to 10 dummy = SPI_IO(&hFF) Next 'I ' '/* now send CMD0 - Reset*/ i= 10 Do Call PutPin(SSEL, LOW) 'Select the CS pin Dummy = MMCCommand(0,0,0) j=10 Do While ((J >0) AND (Dummy <>1)) 'loop for 10 pollings before re-trying 'wait for a "1" return to indicate success J=J-1 Dummy = SPI_IO(&hFF) Loop i = i-1 Call SpiStop() Loop While ((Dummy <> 1) AND (I >0)) If (Dummy <> 1) Then MMCInit = -1 'MMC RESET CMD not accepted End If 'Now put into "Idle" state Call PutPin(SSEL, LOW) 'Select the CS pin ' /* send CMD1 until we get a 0 back, indicating card is done initializing */ I = 10 Do Dummy = MMCCommand(1,0,0) If (Dummy > 0) then Dummy = MMCWaitSuccess(10) End If I = I-1 Loop While ((Dummy > 0) AND (I > 0)) if (Dummy > 0) then MMCInit = MMCInit - 2 'Init Fail Else MMCInit = 0 'init good End If Call SpiStop() End Function '************************************************************ '* void MMCInfo(void) '* '* - gets and prints formatted CID and CSD info from card '************************************************************/ Public Sub MMCInfo() 'CID = 16 bytes Dim I as Integer Dim J as Byte Dim Dummy as Byte Call PutPin(SSEL, LOW) 'Select the CS pin to start transaction J = 100 Do J = J-1 Dummy = MMCCommand(10,0,0) If (Dummy <>254) then Dummy = MMCWaitReady(10) 'should get a valid byte within 10 pollings End If Loop While ((J>0) AND (Dummy <>254)) if (Dummy <> &hFE) Then Debug.Print "MMC: error during CID read" Else Debug.Print "MMC: Good CID read "; End If 'Show the values For I=1 To 16 Debug.print CStr(SPI_IO(&hff));" "; Next debug.print " " Call SpiStop End Sub '***************************************** '* '* Read the CSD register '* '***************************************** Public Sub MMCCSD() 'CSD = 16 bytes Dim I as Integer Dim J as Byte Dim Dummy as Byte J = 100 Do J = J-1 Dummy = MMCCommand(9,0,0) 'if (Dummy >0) Then Dummy = MMCWaitReady(10) 'should get a valid byte within 10 pollings 'End If Loop While ((J>0) AND (Dummy <>254)) if (Dummy <> &hFE) Then Debug.Print "MMC: error during CSD read" Else Debug.Print "MMC: Good CSD read "; End If 'Show the values For I=1 To 16 Debug.print CStr(SPI_IO(&hff));" "; Next debug.print " " Call SpiStop End Sub '************************************************************ '* Set Block Length CMD16 '* '* Sets the block length '* takes unsigned long length. Unknown how it will work with >512 byte sizes '************************************************************/ Public Function MMCSetBlockLen(ByVal lba as unsignedlong) as Integer Dim I as byte Dim J as Byte Dim Dummy as Byte Call PutPin(SSEL, LOW) 'Select the CS pin to start transaction j = 10 Do J = J-1 Dummy = MMCCommand(16,Hiword(lba), LoWord(lba)) if (Dummy > 0) Then Dummy = MMCWaitSuccess(10) End If Loop While ((J > 0) and (Dummy >0)) If (Dummy = 0) then MMCSetBlockLen = 0 'success Else MMCSetBlockLen = -1 'failed End If Call SpiStop() End Function '************************************************************ '* int MMCReadSector(unsigned long lba, unsigned char * s) '* '* - reads a sector from the card (512 bytes) '* - takes Byte # as param does not check block alignment '************************************************************/ Public Function MMCReadSector(ByVal lba as unsignedlong, ByRef Buffer() as Byte) as Integer Dim Index as Integer Dim J as byte Dim Dummy as Byte Call PutPin(SSEL, LOW) 'Select the CS pin to start transaction J = 20 do Dummy = MMCCommand(17,Hiword(lba), LoWord(lba)) J = J-1 if (dummy <>254) Then Dummy = MMCWaitReady(10) End If Loop while ((J>0) AND (Dummy <>254)) If (Dummy <>254) then MMCReadSector = -1 'failed to get successful transimssion of request Exit Function end if for J=1 to 7 for Index = 1 to 73 '/* read the sector */ 'Buffer(Index) = SPI_IO(&hff) Debug.Print Chr(SPI_IO(&hFF)); 'just print the data for now. Next 'index Debug.print next 'j Debug.Print Chr(SPI_IO(&hFF)); 'get the last character Dummy = SPI_IO(&Hff) '/* checksum -> don't care about it for now */ Dummy = SPI_IO(&hff) '/* checksum -> don't care about it for now */ MMCReadSector = 0 Call SpiStop() End Function '************************************************************ '* int MMCWriteSector(unsigned long lba, unsigned char * s) '* '* - Writes a sector from the card (512 bytes) '* - takes Byte # as param does not check block alignment '* - Takes a buffer as a possible data source '************************************************************/ Public Function MMCWriteSector(ByVal lba as UnsignedLong, ByRef Buffer() as Byte) as Integer Dim Index as UnsignedInteger Dim J as Byte Dim Dummy as Byte Call PutPin(SSEL, LOW) 'Select the CS pin to start transaction J = 10 do Dummy = MMCCommand(24,Hiword(lba), LoWord(lba)) J = J-1 Dummy = MMCWaitSuccess(200) 'wait for successful transmission Loop while ((J>0) AND (Dummy >0)) If (Dummy > 0) Then MMCWriteSector = -1 'failed to get successful command Exit Function End If Dummy = SPI_IO(&hFF) 'send a dummy byte Dummy = SPI_IO(&hfe) '// Send Start Byte For Index = 1 to 512 '/* write the sector */ 'Dummy = SPI_IO(Buffer(index)) 'this will write using the entire buffer 'Dummy = SPI_IO(Cbyte(index \2)) 'Fill the sector with incrementing bytes 'Dummy = SPI_IO(bx1010_0101) 'send an arbitrary bit pattern 165d dummy = SPI_IO(0) 'fill with zeros Next Dummy = SPI_IO(&hff) '/* checksum -> don't care about it for now */ Dummy = SPI_IO(&hff) '/* checksum -> don't care about it for now */ Dummy = SPI_IO(&hff) '/* Read "data response byte" */ Index = 5000 Do While ((SPI_IO(&hFF) = 0) AND (Index > 0)) 'wait for data to finish Index = Index - 1 Loop If Index = 0 Then 'Loop Times out: ERROR MMCWriteSector = -1 Else MMCWriteSector = 0 'Success End if Call SpiStop() End Function '************************************************************ ' * void MMCCommand(unsigned char command, unsigned int px, unsigned int py) ' * ' * - send one byte of 0xff, then issue command + params + (fake) crc ' * - eat up the one command of nothing after the CRC ' ************************************************************/ Public Function MMCCommand(ByVal command as Byte, _ ByVal px as UnsignedInteger, _ ByVal py as UnsignedInteger) as Byte Dim Dummy as Byte Call PutPin(SSEL, LOW) 'Select the CS pin Dummy = SPI_IO(&Hff) Dummy = SPI_IO(command OR &H40) Dummy = SPI_IO(HiByte(px)) Dummy = SPI_IO(LoByte(px)) Dummy = SPI_IO(HiByte(py)) Dummy = SPI_IO(LoByte(py)) Dummy = SPI_IO(&H95) '/* correct CRC for first command in SPI */ '/* after that CRC is ignored, so no problem with */ '/* always sending 0x95 */ MMCCommand = Dummy End Function '************************************* '* poll until a zero is received '* '* parameters are # of iterations allowed '************************************* private Function MMCWaitSuccess(byval index as Integer) as Byte Do While ((index >0) AND (SPI_IO(&hFF) > 0)) Index = Index-1 Loop If (Index > 0) then MMCWaitSuccess = 0 Else MMCWaitSuccess = &hFF End If End Function '************************************* '* poll until a "Data Ready" (254) is received '* '* parameters are # of iterations allowed '************************************* private Function MMCWaitReady(byval Index as Integer) as Byte Do While ((index >0) AND (SPI_IO(&hFF) <> &hFE)) Index = Index-1 Loop If (Index > 0) then MMCWaitReady = &hFE Else MMCWaitReady = &hFF End If End Function '******************************************************** '* Main SPI routine '* -Transmits a byte and receives a byte simultaneously '* -Received byte is returned '* -If you only want to read a byte, put a dummy (0XFF) in the transmit slot '******************************************************** ' Get SPI Bit ' Entry: RB = SPI Receive Byte ' Exit : Updated Byte Private Function Get_SPI_Bit(ByRef RB As Byte) As Byte RB = RB * 2 + GetPin(MISO) ' Shift-in Bit from Slave Get_SPI_Bit = RB End Function '***************************************************** '* Deactivate the SPI connection to the MMC Card * '* -Deselect and send 8 clocks by sending a byte * '***************************************************** Public Sub SpiStop() Dim Dummy as Byte Call PutPin(SSEL, HIGH) 'Deselect the CS pin Dummy = SPI_IO (&hFF) End Sub ' SPI Bit-Banged Interface ' Assumes Bits are Sent and Received MSbit first ' Assumes standard MMC bus configuration (CPOL = 0 (MOSI low at idle), Phasing = 1 (Falling edge)) 'Pin25 is RED LED 'Pin26 is GREEN LED '****************************************************************** ' Intitialize SPI Public Sub Init_SPI() Call PutPin(SSEL, bxOutputHigh) ' Set Slave-Select to Output-High Call PutPin(MISO, bxInputTristate) ' Set MISO to Input-Tristate Call PutPin(SCLK, bxOutputLow) ' Set SPI Clock Idle State End Sub '********************************************************************* ' Send and Receive SPI Byte ' Setup: ' : SSEL = Low ' Entry: SB = Byte to Send ' Exit : Returns Byte Received Public Function SPI_IO(ByVal SB As Byte) As Byte Dim RB As Byte ' SPI Receive Byte Dim I As Byte For I = 1 to 8 ' Shift 8 Bits If ((SB AND bx1000_0000 ) > 0) Then ' Isolate Bit and Shift-out to Slave Call PutPin(MOSI, bxOutputHigh) Else Call PutPin(MOSI, bxOutputLow) End If SB = SB * 2 ' Shift Send Byte Bit to Left RB = Get_SPI_Bit(RB) Call PutPin(SCLK, bxOutputHigh) ' Set SCLK High Call PutPin(SCLK, bxOutputLow) ' Set SCLK Low Next SPI_IO = RB End Function '00062 // MMC commands (taken from sandisk MMC reference) '00063 #define MMC_GO_IDLE_STATE 0 ///< initialize card to SPI-type access '00064 #define MMC_SEND_OP_COND 1 ///< set card operational mode '00065 #define MMC_SEND_CSD 9 ///< get card's CSD '00066 #define MMC_SEND_CID 10 ///< get card's CID '00067 #define MMC_SEND_STATUS 13 '00068 #define MMC_SET_BLOCKLEN 16 ///< Set number of bytes to transfer per block '00069 #define MMC_READ_SINGLE_BLOCK 17 ///< read a block '00070 #define MMC_WRITE_BLOCK 24 ///< write a block '00071 #define MMC_PROGRAM_CSD 27 '00072 #define MMC_SET_WRITE_PROT 28 '00073 #define MMC_CLR_WRITE_PROT 29 '00074 #define MMC_SEND_WRITE_PROT 30 '00075 #define MMC_TAG_SECTOR_START 32 '00076 #define MMC_TAG_SECTOR_END 33 '00077 #define MMC_UNTAG_SECTOR 34 '00078 #define MMC_TAG_ERASE_GROUP_START 35 ///< Sets beginning of erase group (mass erase) '00079 #define MMC_TAG_ERARE_GROUP_END 36 ///< Sets end of erase group (mass erase) '00080 #define MMC_UNTAG_ERASE_GROUP 37 ///< Untag (unset) erase group (mass erase) '00081 #define MMC_ERASE 38 ///< Perform block/mass erase '00082 #define MMC_CRC_ON_OFF 59 ///< Turns CRC check on/off '00083 // R1 Response bit-defines '00084 #define MMC_R1_BUSY 0x80 ///< R1 response: bit indicates card is busy '00085 #define MMC_R1_PARAMETER 0x40 '00086 #define MMC_R1_ADDRESS 0x20 '00087 #define MMC_R1_ERASE_SEQ 0x10 '00088 #define MMC_R1_COM_CRC 0x08 '00089 #define MMC_R1_ILLEGAL_COM 0x04 '00090 #define MMC_R1_ERASE_RESET 0x02 '00091 #define MMC_R1_IDLE_STATE 0x01 '00092 // Data Start tokens '00093 #define MMC_STARTBLOCK_READ 0xFE ///< when received from card, indicates that a block of data will follow '00094 #define MMC_STARTBLOCK_WRITE 0xFE ///< when sent to card, indicates that a block of data will follow '00095 #define MMC_STARTBLOCK_MWRITE 0xFC '00096 // Data Stop tokens '00097 #define MMC_STOPTRAN_WRITE 0xFD '00098 // Data Error Token values '00099 #define MMC_DE_MASK 0x1F '00100 #define MMC_DE_ERROR 0x01 '00101 #define MMC_DE_CC_ERROR 0x02 '00102 #define MMC_DE_ECC_FAIL 0x04 '00103 #define MMC_DE_OUT_OF_RANGE 0x04 '00104 #define MMC_DE_CARD_LOCKED 0x04 '00105 // Data Response Token values '00106 #define MMC_DR_MASK 0x1F '00107 #define MMC_DR_ACCEPT 0x05 '00108 #define MMC_DR_REJECT_CRC 0x0B '00109 #define MMC_DR_REJECT_WRITE_ERROR 0x0D '00110