MEL PICBASIC Forum - EEPROM automatic identification routine


  • EEPROM automatic identification routine

    Here is my final version of the EEPROM automatic identification routine. The problem: I2C EEPROM don't have embedded ID code and it is not possible to detect which type of EEPROM is connected to a PIC. Since different size EEPROMs require different variables to be used, the code can only accommodates for a single type of EEPROM size. The topic was previously discussed here: Auto-Dectect EEProm Size. However I found out that melanie's routine does not work as expected. I got a hand on smaller EEPROMs and especially a 24C01 and found out that small EEPROMs wrap the memory space in a strange way, and the last byte of a non-existing byte reads $01 regardless of the value programmed in what would be it's mirror in existing memory space. This may be due to the change in address space, because wrapping does work as expected on 24C16 through 24C512 (should also work with 24C08 but not tested).

    Let me do a modest contribution by wrapping it all into a single routine that identify everything from 24LC00 to 24LC512. This is provided that pins A0, A1, and A2 of the I2C memory = 0 (grounded). A later evolution would be to add address detection as well.


    <<< DOWNLOAD THE FILE HERE: EEPROM_detect.pbp >>>

    SOURCE CODE:
    Code:
    '***************************************************************************
    '*  Name    : EEPROM_detect.pbp                                            *
    '*  Author  : Antoine Bercovici                                            *
    '*  Date    : 02/10/2010                 iEMMMt                            *
    '*  Version : 1.1                ......UMMMMMMMMMM.                        *  
    '*                         .,:i,:.. .      .;AMMMMMMS                      *
    '*                       :i:..                  .WMMMM@                    *
    '*                    .i;.    .  YMMMMMMMWv        YMMMMMi                 *
    '*                  i:;.   ..... @M#UU0MMMMMU  ...   0MMMMMZ               *
    '*              :EMMM,  .........        oMMM0 .,.,.. oMMMMMMM             *
    '*          i@MMMMMM   ...........   .    MMMM ii;i;:, MMMMMMMM            *
    '*        #MMMMMMMMS  ..........,.,.  .iBMMMM:.:iiiii,.7MMMMMMMM#          *
    '*        MMMMMMMMMA  .......,,iii,iMMMMMMM0 .:ii;iiii.oMMMMM@SM#          *
    '*       .MMMMMMMMMM   ...,.i:;ii:.7MMMAv.  ,:ii;i;ii,,MMMMM2  vM.         *
    '*       CM6AMMMMMMMU   .,,ii;ii:: .;   .,,ii;i;;;i;:i,MM#i ,M#@$          *
    '*       #M:  0MMMMMM@. ..iiiiii::MMMMM.ii;;;;;i;ii,iviQB    MM0@          *
    '*       WM     vMMMMMM0. ..,iii,,MMMMM::;i;i;i;i;vb@@#@I    XQ@Mi         *
    '*                :MMMMMMMS.  ..,. :ci.,i::,,.:v7icM@bb@#      MM1         *
    '*                   @MMMMMMMM097;,..:i;ii;Yn$@n7;.MM#W0.      BM$         *
    '*                     0MMMMMMMMMzzMM7XvQMMMMMM.i,. .#MY       tMM         *
    '*                       CMMMMM@C2WMM .. MM$W@o      nM#        @E         *
    '*                         .6i  WMBBS    ,o$@v       .MM.                  *
    '*                              ,@U#0      bMb        @M,                  *
    '*                               M@S       iM@         .                   *
    '*                               BMn        MM.                            *
    '*                               7M$        ib                             *
    '*                               .MM                                       *
    '*                                C6                                       *
    '*                                                                         *
    '*  USAGE  1. Place INCLUDE EEPROM_detect.pbp within your program and      *
    '*            modify the user defined variable below to suit your program  *
    '*         2. Call first ReadMemoryIDTag routine to identify the EEPROM by *
    '*            its ID tag. If no ID tag is present the program will perform *
    '*            data destructive identification on the EEPROM followed by a  *
    '*            complete erase. Result of identification is given by         *
    '*            variables MemType, MemSize and PageSize                      *
    '*         3. Call MemoryErase when you need to perform full erase         *
    '*         4. Call MemoryRead when you need to read data at MemAddressLong *
    '*            address. Data is retrieved in DataValue                      *
    '*         5. Call MemoryWrite to write DataValue at MemAddressLong        *
    '***************************************************************************
    
    '*******************************************************
    'Variable declaration for controlling the EEPROM
    '*******************************************************
    MemAddressLong      VAR WORD '16 bit address variable for memory from 24C32 to 24C512
    MemAddress          VAR BYTE '8 bit address variable for memory up to 24C16
    Control             VAR BYTE 'Control byte for EEPROM test
    MemType             VAR BYTE 'Type of memory after size control: 11=24C00, 10=24C01, 9=24C02, 8=24C04, 7=24C08, 6=24C16, 5=24C32, 4=24C64, 3=24C128, 2=24C256, 1=24C512
    PageSize        	VAR BYTE 'Size of memory pages in bytes
    PageSizeBis     	VAR BYTE 'For internal use
    MemSize             VAR WORD 'Size of EEPROM in bytes
    Blank               VAR BYTE [16] 'Define EEPROM blanking array
    WriteDelay          VAR BYTE 'Delay after writing to EEPROM
    TagAddress          VAR BYTE 'EEPROM ID tag
    DataValue           VAR BYTE 'Data to be written in EEPROM
    InternalCounter     VAR BYTE 'For internal use
    
    '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    'MODIFY THESE VARIABLES TO SUIT YOUR APPLICATION
    '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    SCLpin              VAR PORTB.6 'SCL Pin
    SDApin              VAR PORTB.4 'SDA Pin
    
    Writedelay = 5 			'Use a 5ms delay between write operations, Increase to 10 if needed by your EEPROM
    TagAddress = 12			'EEPROM address where you want to record your ID tag (from 0 to 15, limited by 24C00)
    
    '*******************************************************
    'EEPROM Size detection for 24C16 and smaller (8bit Address)
    '*******************************************************
    MemorySizeCheck:
    
    FOR InternalCounter = 6 to 11
    	MemAddress = 255
    	Control = %10100000
    	If InternalCounter = 6 then Control = %10101110
    	If InternalCounter = 7 then Control = %10100110
    	If InternalCounter = 8 then Control = %10100010
    	IF InternalCounter = 10 THEN MemAddress = 127
    	IF InternalCounter = 11 THEN MemAddress = 15
    	I2CWRITE SDApin, SCLpin, Control, MemAddress, [InternalCounter]
    	PAUSE WriteDelay
    NEXT InternalCounter
    
    I2CRead SDApin, SCLpin, %10101110, 255, [MemType]
    IF MemType = 6 THEN GOTO DoneChecking
    I2CRead SDApin, SCLpin, %10100110, 255, [MemType]
    IF MemType = 7 THEN GOTO DoneChecking
    I2CRead SDApin, SCLpin, %10100010, 255, [MemType]
    IF MemType = 8 THEN GOTO DoneChecking
    I2CRead SDApin, SCLpin, %10100000, 255, [MemType]
    IF MemType = 9 THEN GOTO DoneChecking
    I2CRead SDApin, SCLpin, %10100000, 127, [MemType]
    IF MemType = 10 THEN GOTO DoneChecking
    I2CRead SDApin, SCLpin, %10100000, 15, [MemType]
    IF MemType = 11 THEN GOTO DoneChecking
    
    IF MemType < 6 OR MemType > 11 THEN
    	GOSUB BigMemorySizeCheck
    ENDIF
    
    '*******************************************************
    'EEPROM Size detection for 24C32 to 24C512 (16bit Address)
    '*******************************************************
    
    MemAddressLong = 65535
    
        FOR InternalCounter = 1 TO 5
    	   Control = %10100000
    	   I2CWRITE SDApin, SCLpin, Control, MemAddressLong, [InternalCounter]
            MemAddressLong = MemAddressLong >> 1
    	   PAUSE WriteDelay
        NEXT InternalCounter
    
    MemAddressLong = 65535
    
    I2CRead SDApin, SCLpin, Control, MemAddressLong, [MemType]
    
    ENDIF
    
    DoneChecking:
    
    IF MemType = 0 OR MemType > 10 THEN
        MemSize = 0
        IF MemType = 11 THEN MemSize = 15
    ELSE
        MemSize = 65535 >> (MemType - 1)
    ENDIF
    
    IF (MemType > 10) OR (MemType = 0) THEN
        PageSize = 0
    ELSE
        PageSize = 8
        IF MemType < 9 THEN PageSize = 16
        IF MemType < 6 THEN PageSize = 32
        IF MemType < 4 THEN PageSize = 64
        IF MemType = 1 THEN PageSize = 128
    ENDIF
    
    RETURN
    
    '*******************************************************
    'Read EEPROM
    '*******************************************************
    MemoryRead:
    
    Control = 160
    SELECT CASE MemType
    	CASE 11, 10, 9, 8, 7, 6
    	   MemAddress = MemAddressLong.byte0
    	   IF MemAddressLong.8 = 1 THEN Control = Control + 2
    	   IF MemAddressLong.9 = 1 THEN Control = Control + 4
    	   IF MemAddressLong.10 = 1 THEN Control = Control + 8
    	   I2CREAD SDApin, SCLpin, Control, MemAddress, [DataValue]
    	CASE 5, 4, 3, 2, 1
    	   I2CREAD SDApin, SCLpin, Control, MemAddressLong, [DataValue]
    END SELECT
    
    RETURN
    
    '*******************************************************
    'Write EEPROM
    '*******************************************************
    MemoryWrite:
    
    Control = 160
    SELECT CASE MemType
    	CASE 11, 10, 9, 8, 7, 6
    	   IF MemAddressLong.8 = 1 THEN Control = Control + 2
    	   IF MemAddressLong.9 = 1 THEN Control = Control + 4
    	   IF MemAddressLong.10 = 1 THEN Control = Control + 8
    	   MemAddress = MemAddressLong.byte0
    	   I2CWRITE SDApin, SCLpin, Control, MemAddress, [DataValue]
    	CASE 5, 4, 3, 2, 1
    	   I2CWRITE SDApin, SCLpin, Control, MemAddressLong, [DataValue]
    END SELECT
    
    PAUSE WriteDelay
    
    RETURN
    
    '*******************************************************
    'Erase EEPROM
    '*******************************************************
    MemoryErase:
    
    GOSUB MemorySizeCheck
    
    For InternalCounter = 0 to 15 'Fill Blank array with blank data for EEPROM
    Blank[InternalCounter] = $FF
    Next InternalCounter
    
    SELECT CASE MemType
    	CASE 11
    	   Control = 160
    	   For MemAddress = 0 TO MemSize
    	       I2CWRITE SDApin, SCLpin, Control, MemAddress, [$FF]
                Pause WriteDelay
            NEXT MemAddress			
    	CASE 10, 9, 8, 7, 6
            PageSizeBis = PageSize / 2
            For Control = 160 TO 174 STEP 2
                FOR MemAddress = 0 to MemSize Step PageSize
                    I2CWRITE SDApin, SCLpin, Control, MemAddress, [STR Blank\PageSizeBis, STR Blank\PageSizeBis]
                    Pause WriteDelay
                NEXT MemAddress
    		IF MemType = 1 OR MemType = 2 THEN GOTO WriteMemoryIDTag
    		IF MemType = 3 AND Control = 162 THEN GOTO WriteMemoryIDTag
    		IF MemType = 4 AND Control = 166 THEN GOTO WriteMemoryIDTag
    	NEXT Control
    	CASE 5, 4, 3, 2, 1
            PageSizeBis = PageSize / 8
            FOR MemAddressLong = 0 to MemSize Step PageSize
                I2CWRITE SDApin, SCLpin, 160, MemAddressLong, [STR Blank\PageSizeBis, STR Blank\PageSizeBis,_
                                                                STR Blank\PageSizeBis, STR Blank\PageSizeBis,_
                                                                STR Blank\PageSizeBis, STR Blank\PageSizeBis,_ 
                                                                STR Blank\PageSizeBis, STR Blank\PageSizeBis]
            Pause WriteDelay
        NEXT MemAddressLong
    END SELECT
    
    WriteMemoryIDTag:
    MemAddressLong = TagAddress
    DataValue = MemType
    GOSUB MemoryWrite
    
    RETURN
    
    '*******************************************************
    'Retrieve preprogrammed EEPROM ID tag at address TagAddress
    '*******************************************************
    ReadMemoryIDTag:
    MemAddress = TagAddress
    
    I2CREAD SDApin, SCLpin, %10100000, MemAddress, [MemType]
    IF MemType = 0 OR MemType > 11 THEN
    	MemAddressLong = TagAddress
    	I2CREAD SDApin, SCLpin, %10100000, MemAddressLong, [MemType]
    	IF MemType = 0 OR MemType > 11 THEN
    		GOSUB MemoryErase
    	ENDIF
    ENDIF
    GOSUB DoneChecking
    
    RETURN
    USAGE:

    Note that the EEPROM detection routine does erase part of the data, and should not be used on a memory that contain code. To perform a "data safe" identification, a location in EEPROM is chosen for subsequent ID.
    1. Place EEPROM_detect.pbp within your project file and call INCLUDE EEPROM_detect.pbp within your program. Some declarations needs to be modified within EEPROM_detect.pbp: change SDApin and SCLpin to match your I/O ports, and declare an EEPROM address where you'd like the ID tag to be stored (provided it exists in the smallest memory, the 24C00).

    2. Call first ReadMemoryIDTag routine in your program initialization to identify the EEPROM by its ID tag. If no ID tag is present the program will perform data destructive identification on the EEPROM followed by a complete erase. Result of identification is given by the following variables:

      MemType (11=24C00, 10=24C01, 9=24C02, 8=24C04, 7=24C08, 6=24C16, 5=24C32, 4=24C64, 3=24C128, 2=24C256, 1=24C512)

      MemSize (15, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 0=detection failed) in bits

      PageSize (0, 8, 16, 32, 64, 128) in bytes per pages

    3. Call MemoryErase routine when you need to perform full memory erase within your program. A 24C512 takes about 5 seconds to be erased with page-write mode.

    4. Call MemoryRead routine when you need to read data. Use MemAddressLong variable (WORD) as your address pointer, data will be dumped in DataValue.

    5. Call MemoryWrite routine when you need to write data. Use MemAddressLong variable (WORD) as your address pointer, place data in DataValue.

    SAMPLE CODE:

    Below is a quick and dirty little example that identify an EEPROM and display results on LCD (add all the defines for your LCD).

    Code:
    '*******************************************************
    'Display EEPROM size on LCD
    '*******************************************************
    INCLUDE EEPROM_detect.pbp
    
    GOSUB ReadMemoryIDTag
    
    LCDOUT $FE,1, "Memory type:"
    Select CASE MemType
    	CASE 11
    	LCDOUT $FE,$C0, "24LC00, 16B"
    	CASE 10
    	LCDOUT $FE,$C0, "24LC01, 128B"
    	CASE 9
    	LCDOUT $FE,$C0, "24LC02, 256B"
    	CASE 8
    	LCDOUT $FE,$C0, "24LC04, 512B"
    	CASE 7
    	LCDOUT $FE,$C0, "24LC08, 1kB"
    	CASE 6
    	LCDOUT $FE,$C0, "24LC16, 2kB"
    	CASE 5
    	LCDOUT $FE,$C0, "24LC32, 4kB"
    	CASE 4
    	LCDOUT $FE,$C0, "24LC64, 8kB"
    	CASE 3
    	LCDOUT $FE,$C0, "24LC128, 16kB"
    	CASE 2
    	LCDOUT $FE,$C0, "24LC256, 32kB"
    	CASE 1
    	LCDOUT $FE,$C0, "24LC512, 64kB"
    	CASE ELSE
    	LCDOUT $FE,$C0, "Not recognized"
    END SELECT
    This article was originally published in forum thread: Auto-Dectect EEProm Size started by DynamoBen View original post