' Program: MMC3V.BAS written using PicBasicPro ver 2.40 ' PicBasic Pro program to interface with a Sandisk ' MMC module using the SPI protocol. ' ' BETA CODE ' ************* NOT FOR COMMERCIAL USE ************************* ' Ver. 0.1.31 Nov, 2001 ' ' Proprietory Owner: COMPsys, Copyright 2001 ' ' Project Reference: MMC3V-F876 ' MCU: Microchip PIC16F876 ' Software: Compiler PBP V.2.40, IDE MBLAB Ver 5 ' PIC Programmer: EPIC used to load the bootloader, ' Custom PCB with a serial interface ' for ISP and terminal output ' ' Initial Date: OCT 28, 2001 ' Projected Completion Date: Unknown ' ' Author: Ranjit Diol ' rsdiol@compsys1.com ' http://www.compsys1.com/workbench ' '--------------------------------------------------------------- ' (c) COMPSys, 2001 ' All Rights Reserved '*************************************************************** ' DISCLAIMER: This file is being released as non-commericial ' freeware. It is being provided "AS IS", neither the author, ' nor COMPSys shall be held liable for any damages caused directly ' or indirectly by its use. '*************************************************************** 'Brief: The MMC is a 3volt part therefore all data lines ' must be conditioned if interfacing with a 5v mcu. ' ' MMC pins in SPI mode: ' Pin1:ChipSelect(SS),Pin2:MMC input(MOSI),Pin3:GND,Pin4:3V+, ' Pin5:Clock(SCK), Pin6:GND, Pin7:MMC output(MISO) ' PIC pins: ' Portd.7 SS,Portd.6 SCK,Portd.5 MOSI, Portd.4 MISO ' ' For voltage translation: ' An LM317 or LM2937-3.3 can be used to provide 3.3 volts ' for the MMC and four 2N3904 transistors with resistors ' can be used forfor MMC power and data line conditioning ' See the SanDisk website for more details ' http://www.sandisk.com '============================================================== ' ' I M P O R T A N T ' PLEASE NOTES ' ************** This code is written for a PIC16F876 operating on 3.3volts ************** @ device pic16F876, xt_osc, wdt_on, pwrt_off, bod_off, lvp_off, cpd_off, wrt_off, protect_off ' **************************************************************************************** ' ' This application uses a external 3.3v FRAM FM24CL64 for temporary storage ' which does not require a wait state after a write and it does not have ' any limit on the number of lifetime writes! ' ' IF YOU USE a standard I2C EEprom you will have to insert a 5 or 10 ms pause ' after each write statement depending on the eeprom used. ' '****************************************************************************************** DEFINE ONINT_USED 1 'If using ISP DEFINE OSC 10 'Adjust to suit your design ADCON1 = 7 'Adjust ADC for your needs '***************************** include "modedefs.bas" 'I2C Variables ctl con $A0 'EEPROM control code edata var BYTE 'Data byte to be written '***************** PIC PIN ASSIGNMENTS ***************** 'I2C Eeprom Pins scl var PORTC.3 'I2C SCL for ext eeprom sda var PORTC.4 'I2C SDA for ext eeprom 'Serial Pins out_pin var PORTC.6 'Serial OUT pin in_pin var PORTC.7 'Serial IN pin ser_baud con 32 '19200 Baud TRISC.0 = 1 'SO Set pin directions TRISC.1 = 0 TRISC.2 = 0 TRISC.5 = 0 'MMC Connections SCK var PORTC.1 ' Clock pin MMC pin 5 SO var PORTC.0 ' Data from MMC pin 7 SS var PORTC.5 ' Slave select pin 1 SI var PORTC.2 ' Data to MMC pin 2 '***************** General MMC Variables used ************************** 'Variables used (may be some that are no longer in use -- haven't cleaned up as yet!) mmc_status var byte mmc_status = $0000 addr var word addr_H var word ' MMC Address is a 32 bit address, addr_h is bits 31-16 addr_L var word ' and addr_l is is bits 0-15 arg0 var byte ' args used arg1 var byte arg2 var byte arg3 var byte arg4 var byte cmd var byte 'command var crc var byte 'crc var dat var byte 'data var i var byte 'counter var x var word 'counter var y var byte 'counter var res var byte 'response var reswr var byte 'response w/r res2 var word 'response var erase_flag var byte erase_flag = 0 eaddr1 var word 'ext eeprom addr vars eaddr2 var word e_addr var word in_dat var byte 'Serial vars chk var byte cntr var byte addr = $0000 'Used for eeprom etc pause 500 'Let things settle a bit 'For debugging serout2 out_pin,ser_baud,["Start",10,13] 'Display on terminal ' ***** Jump over the subroutines ************** goto main 'Initialize MMC init_mmc: SS = 1 dat =$ff cntr = 10 gosub shiftout_dat ss = 0 pause 50 cmd = $40 'MMC Command 0 crc = $95 cmd0: dat = cmd Shiftout SI, SCK, MSBFIRST,[dat] dat = 0 cntr = 4 gosub shiftout_dat dat = crc Shiftout SI, SCK, MSBFIRST,[dat] chk = 1 gosub chk_res ss = 1 pause 50 ss = 0 CMD1: 'TO DO: Need to insert a 'time-out' after 255 attempts and branch to error routine while res <> 0 ss = 1 dat = $ff Shiftout SI, SCK, MSBFIRST,[dat] gosub shiftin_res ss = 0 dat = $41 'MMC Command 1 Shiftout SI, SCK, MSBFIRST,[dat] 'arg4 = $41 'gosub shiftout1 dat = 0 cntr = 4 gosub shiftout_dat dat = $ff gosub shiftout2 gosub shiftin_res wend dat = $ff 'MMC now successfully initialized in SPI mode 'For debugging serout2 out_pin,ser_baud,["INIT OK!",10,13] 'Display on terminal return 'MMC Writing subroutine write 512 bytes stored in the I2C eeprom 'This routine will write whatever is in I2C eeprom locations eaddr1 to eaddr2 'Check response chk_res: 'TO DO: Need to insert a 'time-out' after 255 attempts and branch to error routine while res <> chk Shiftin SO, SCK, MSBPRE, [res] wend return mwrite: ss = 1 arg4 = $ff gosub shiftout1 gosub shiftin_res ss = 0 arg0 = $58 arg1 = addr_H.BYTE1 arg2 = addr_H.BYTE0 arg3 = addr_L.BYTE1 arg4 = addr_L.BYTE0 gosub shiftout5 arg4 = $ff gosub shiftout1 gosub shiftin_res chk = 0 gosub chk_res 'Write command was a success 'File token tells the MMC data is to follow arg4 = $FE gosub shiftout1 'MMC now ready to write data in blocks of 512 bytes assumes eeprom address in eaddr1, eaddr2 for addr = eaddr1 to eaddr2 'READ addr,dat 'Read from internal eeprom if it has 512 byte capacity I2CREAD sda,scl,ctl,addr,[dat] 'Read from I2C ext eeprom Shiftout SI, SCK, MSBFIRST,[dat] next addr dat=$ff cntr = 2 gosub shiftout_dat gosub shiftin_res y=res & $0f gosub shiftin_res 'TO DO: Need to insert a 'time-out' after 255 attempts and branch to error routine while res = 0 'MMC is busy writing until response is not = 0 Shiftin SO, SCK, MSBPRE, [res] wend gosub mstatus 'Get write status return 'MMC Reading routine, assumes addr_H and addr_L have the MMC 32 bit address mread: ss = 1 arg4 = $ff gosub shiftout1 gosub shiftin_res ss = 0 arg0 = $51 arg1 = addr_H.BYTE1 arg2 = addr_H.BYTE0 arg3 = addr_L.BYTE1 arg4 = addr_L.BYTE0 gosub shiftout5 arg4 = $ff gosub shiftout1 gosub shiftin_res chk = 0 gosub chk_res chk = $FE gosub chk_res 'Read cmd successful 'Read the MMC data and save in eeprom assumes eaddr1 and eaddr2 is given for e_addr = eaddr1 to eaddr2 'We will read 512 bytes can be any number Shiftin SO, SCK, MSBPRE, [dat] 'We now have a byte do something with it! I2CWRITE sda,scl,ctl,e_addr,[dat] 'Write to eeprom from eaddr1 to eaddr2 next e_addr 'Required after a MMCread gosub shiftin_res gosub shiftin_res gosub mstatus 'Get read status return 'Set block length (must lie with sector boundaries minimum default is 512) mset_blk: 'Cmd16: cmd = $50 crc = $ff gosub send_cmd return 'MMC tag beginning and end of an earse block tag_start: 'MMC tag block 'Block START TAG 'Cmd32 cmd = $60 gosub send_cmd return tag_end: 'Cmd33 cmd = $61 gosub send_cmd return 'MMC erase tagged block merase: 'For debugging 'ERASE BLOCK at addr_h,addr_L 'Cmd38 erase_flag = 1 cmd = $66 gosub send_cmd erase_flag = 0 return '============================= 'Send a command to the mmc assumes CMD, addr_H and addr_L send_cmd: ss = 1 arg4 = $ff gosub shiftout1 gosub shiftin_res ss = 0 arg0 = cmd arg1 = addr_H.BYTE1 arg2 = addr_H.BYTE0 arg3 = addr_L.BYTE1 arg4 = addr_L.BYTE0 gosub shiftout5 Dat = $FF cntr = 2 gosub shiftout_dat gosub shiftin_res if erase_flag = 1 then return chk = 0 gosub chk_res return 'MMC status mstatus: ss = 1 dat = $ff Shiftout SI, SCK, MSBFIRST,[dat] gosub shiftin_res ss = 0 arg4 = $4D gosub shiftout1 dat = 0 cntr = 4 gosub shiftout_dat arg4 = $ff gosub shiftout1 Shiftin SO, SCK, MSBPRE, [res2\16] mmc_status = res2 return 'Shift out the same data. Assumes DAT and cntr shiftout_dat: for y = 1 to cntr Shiftout SI, SCK, MSBFIRST,[dat] next y return 'Shift out 5 (ARG0-ARG4) shiftout5: Shiftout SI, SCK, MSBFIRST,[arg0] shiftout4: Shiftout SI, SCK, MSBFIRST,[arg1] shiftout3: Shiftout SI, SCK, MSBFIRST,[arg2] shiftout2: Shiftout SI, SCK, MSBFIRST,[arg3] shiftout1: Shiftout SI, SCK, MSBFIRST,[arg4] return 'Shiftin RES shiftin_res: Shiftin SO, SCK, MSBPRE, [res] return '====================== END OF MMC GENERAL ROUTINES ========================= 'Subroutine used by this application disp: serout2 out_pin,ser_baud,["Data from MMC",10,13] 'Display on terminal 'Display data to terminal, assumes eaddr1,eaddr2 are given for e_addr = eaddr1 to eaddr2 I2CREAD sda,scl,ctl,e_addr,[dat] serout2 out_pin,ser_baud,[dat] 'Display on terminal next e_addr return '*************** M A I N P R O G R A M **************** main: 'Initialize the MMC gosub init_mmc 'Set block length (minimum 512 bytes when writing) default is 512 bytes addr_H = $0000 addr_L = $0200 gosub mset_blk 'Set an I2C eeprom address (512 bytes) eaddr1 = 0 eaddr2 = $01FF 'Load the eeprom with some data to simulate this we 'write 512 bytes to the eeprom Dat = "A" for e_addr = eaddr1 to eaddr2 I2CWRITE sda,scl,ctl,e_addr,[dat] next e_addr 'Set some MMC address 0 - to the end. (However, it must remain within sector boundaries) 'Since we are reading/writing 512 bytes at a time just make sure that the address is a integer 'multiple of 512 bytes. Such as: 0, $0200,$0400...$0A00...$00010A00 etc addr_H = $0001 addr_L = $0000 'Multiple of 512 bytes 'Now transfer the data from the eeprom to the MMC gosub mwrite 'For debugging serout2 out_pin,ser_baud,["Data Written to MMC",10,13] 'Display on terminal 'Next, we read the data back from the MMC and load it into the eeprom 'using the same addresses as above gosub mread 'Now, read it back from the eeprom and display it gosub disp 'If you want to erase the data you need to set the start and end addresses 'But, they must not cross block boundaries '*** Note***** 'If the program hangs at the erase command 'Sandisk documentation states that the erase command in SPI mode can 'sometimes not work correctly. Depends on the version of the card. 'However,it works fine on the Viking MMC's 'For debuggin serout2 out_pin,ser_baud,[10,13,"Erasing...",10,13] 'Finished! 'Set the start erase TAG gosub tag_start 'Set the end erase TAG addr_H = $0001 addr_L = $01FF gosub tag_end 'Issue the erase command gosub merase 'Verify it by reading the MMC again addr_L = $0000 gosub mread 'And finally display the results 'Display data to terminal, assumes eaddr1,eaddr2 are given 'Debugging serout2 out_pin,ser_baud,["Data from MMC after erase",10,13] 'Display on terminal for e_addr = eaddr1 to eaddr2 I2CREAD sda,scl,ctl,e_addr,[dat] serout2 out_pin,ser_baud,[hex2 dat] 'Display on terminal next e_addr 'For debugging serout2 out_pin,ser_baud,[10,13,"All Done!",10,13] 'Finished! end '******************* END OF CODE ************************