How to read & write to a 25aa1024 (1 Mbit SPI Bus Serial EEPROM) via 16F88


Closed Thread
Results 1 to 37 of 37

Hybrid View

  1. #1
    Join Date
    Mar 2003
    Location
    Commerce Michigan USA
    Posts
    1,166

    Default

    wolwil, Here it is again incase you didn't find it. Maxpages is set for 1023 x the number of 24LC1025's you have connected. The routine saves the last storage pointer in the last 2 locations of the last 24LC1025. Block is incremented once for each page. Before you start a clean write you would set block to 0 which is the first page. When you want to read back the data then you would call READ_WRITE_BLK1025 and block would have the last address written..

    This routine is rock solid and I use it for accessing 4 x 24LC1025's for a total of over 4 gigabits of memoy to record Azmnuth,Elevation,East/West/Up/Down Sensor data and control flag information for about 2 months at 1 minute intervals... I hope this helps...

    Code:
     
    CNTRL_BYTE    CON    $A0        'CONTROL BYTE FOR 24LC1025 I2C EEPROM MEMORY (A0/A1 USED FOR CHIP SELECT)
    MAX_PAGES    CON    4095    'MAXIMUM MEMORY STORAGE PAGES,(32 BYTES/MINUTE x 4 MINUTES x PAGES = TOTAL MINUTES)
     
    '*********************************************************************
    RW_EEPROM1025:        'READ FROM or WRITE TO SERIAL EEPROM
    '*********************************************************************
        IF READ_WRITE = 1 THEN    'WRITE 128 BYTE BLOCK TO EEPROM
            IF BLOCK <> 0 THEN    'IF STARTING NEW PASS DON'T READ OLD LOCATION
                READ_WRITE = 0    'SET FOR BLOCK READ
                GOSUB READ_WRITE_BLK1025    'READ FROM SERIAL EEPROM NEXT AVAILABLE STORAGE BLOCK
                READ_WRITE = 1    'SET FOR BLOCK WRITE
            ENDIF
            DEVICE = BLOCK / 512    'SELECT WHICH PHYSICAL ADDRESS BOUNDRY & EEPROM
            ADDRESS = BLOCK << 7    'CALCULATE 12C ADDRESS TO STORE DATA TO
            CNTROL_BYTE = CNTRL_BYTE    'COPY CONTROL BYTE
            CNTROL_BYTE.1 = DEVICE.1    'SET LSB OF HARDWARE ADDRESS
            CNTROL_BYTE.2 = DEVICE.2    'SET MSB OF HARDWARE ADDRESS
            CNTROL_BYTE.3 = DEVICE.0    'SET 64K BLOCK BIT
            INTCON.7 = 0    'CLEAR GLOBAL INTERRUPT
            I2CWRITE SDA,SCL,CNTROL_BYTE,ADDRESS,[STR STOR_DATA\128]    'SAVE DATA TO 12C
            WRITEOCCURED = 1
            INTCON.7 = 1    'SET GLOBAL INTERRUPT
            PAUSE 6        'ALLOW TIME FOR I2C WRITE ~5Ms.
            BLOCK = BLOCK + 1    'INCREMENT FOR NEXT AVAILABLE BLOCK TO WRITE
            BLOCK = BLOCK MIN MAX_PAGES    'LIMIT TO n BLOCKS OF 128 BYTES
            GOSUB READ_WRITE_BLK1025    'WRITE TO or READ FROM SERIAL EEPROM LAST STORAGE BLOCK
        ELSE
            DEVICE = BLOCK / 512    'SELECT WHICH PHYSICAL ADDRESS BOUNDRY & EEPROM
            ADDRESS = BLOCK << 7    'CALCULATE 12C ADDRESS TO STORE DATA TO
            CNTROL_BYTE = CNTRL_BYTE    'COPY CONTROL BYTE
            CNTROL_BYTE.1 = DEVICE.1    'SET LSB OF HARDWARE ADDRESS
            CNTROL_BYTE.2 = DEVICE.2    'SET MSB OF HARDWARE ADDRESS
            CNTROL_BYTE.3 = DEVICE.0    'SET 64K BLOCK BIT
            INTCON.7 = 0    'CLEAR GLOBAL INTERRUPT
            I2CREAD SDA,SCL,CNTROL_BYTE,ADDRESS,[STR READ_DATA\128]    'LOAD IN ENTIRE BLOCK
            WRITEOCCURED = 1
            INTCON.7 = 1    'SET GLOBAL INTERRUPT
        ENDIF
        RETURN
     
    '*********************************************************************
    READ_WRITE_BLK1025:    'WRITE TO or READ FROM SERIAL EEPROM NEXT AVAILABLE STORAGE BLOCK
    '*********************************************************************
        ADDRESS = 65534        'POINT TO LAST STORED DATA(WORD) ADDRESS
        DEVICE = MAX_PAGES / 512    'SELECT WHICH PHYSICAL ADDRESS BOUNDRY & EEPROM
        CNTROL_BYTE = CNTRL_BYTE    'COPY CONTROL BYTE
        CNTROL_BYTE.1 = DEVICE.1    'SET LSB OF HARDWARE ADDRESS
        CNTROL_BYTE.2 = DEVICE.2    'SET MSB OF HARDWARE ADDRESS
        CNTROL_BYTE.3 = DEVICE.0    'SET 64K BLOCK BIT
        IF READ_WRITE = 1 THEN
            INTCON.7 = 0    'CLEAR GLOBAL INTERRUPT
            I2CWRITE SDA,SCL,CNTROL_BYTE,ADDRESS,[BLOCK.LOWBYTE,BLOCK.HIGHBYTE]    'WRITE DATA POINTER TO 12C    
            WRITEOCCURED = 1
            INTCON.7 = 1    'SET GLOBAL INTERRUPT
            PAUSE 6        'ALLOW TIME FOR I2C WRITE ~5Ms.
        ELSE
            INTCON.7 = 0    'CLEAR GLOBAL INTERRUPT
            I2CREAD SDA,SCL,CNTROL_BYTE,ADDRESS,[BLOCK.LOWBYTE,BLOCK.HIGHBYTE]    'READ DATA POINTER FROM 12C    
            WRITEOCCURED = 1
            INTCON.7 = 1    'SET GLOBAL INTERRUPT
        ENDIF
        RETURN
    Dave Purola,
    N8NTA
    Last edited by ScaleRobotics; - 14th June 2010 at 01:24. Reason: Added code tags

  2. #2
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924

    Default

    Hi Dave,
    Thanks for posting your code. I also found my problem...

    My problem is "I am a newbe!!!".
    I forgot PORTF.6 on the 18F6680 is an analog pin.
    RTFD RTFD RTFD

    For what it is worth.. When I take care of the analog issue I can read the part with SHIFTIN/OUT. I can not write to the part that way yet. Still have a timing problem I guess. It may not be worth messing with other than an exercise in coding.
    Dave
    Always wear safety glasses while programming.

  3. #3
    Join Date
    Mar 2010
    Location
    Minnesota, USA
    Posts
    41

    Default

    Quote Originally Posted by Dave View Post
    CNTRL_BYTE CON $A0 'CONTROL BYTE FOR 24LC1025 I2C EEPROM MEMORY (A0/A1 USED FOR CHIP SELECT)
    Maybe this is where I am getting confused... you have the control byte being $A0 which is basically saying to write to the 24LC1025 seeing how the read write bit in that is a 0 like this "10100000" but the you say in your comment that the A0/A1 is for chip select...So in this following line of code where I have the $A0 is that the 8 bit control byte or just the Chip Select portion of it???

    Code:
    I2CREAD PORTB.1,PORTB.4,$A0,addr,[B1]
    See I thought if I wanted to write to chip select A1 I needed to use $A2 or in binary like this %10100010 and if I wanted to read from it I needed to use $A3 or in binary like this %10100011.

    Every combination to read and write to all 4 Chips:

    %10100000 or $A0 = Write to A0 (Pins A0 & A1 Tied Low)
    %10100001 or $A1 = Read from A0
    %10100010 or $A2 = Write to A1 (Pins A0 Tied Low & A1 Tied High)
    %10100011 or $A3 = Read from A1
    %10100100 or $A4 = Write to A2 (Pins A0 Tied High & A1 Tied Low)
    %10100101 or $A5 = Read from A2
    %10100110 or $A6 = Write to A3 (Pins A0 and A1 Tied High)
    %10100111 or $A7 = Read from A3

    So with me having both A0 and A1 Pins Tied to ground I should be using the first 2 options when trying to read/write to the chip or am I just way off on this???

    Am I incorrect in my thinking of what PBP is calling the Control Byte???

  4. #4
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924

    Default

    10100000
    Is the R/W bit. Leave it as "0" and PBP takes care of parsing it to a "1" if needed.

    10100000
    Are the A0 and A1 bits. If pins A0 and A1 are connected to the zero rail leave as zero. Mixing and matching on or the other or both gives the four combination's for up to four chips on the same bus.

    10100000
    Is the bit to set to read or write to the first or second block.
    Dave
    Always wear safety glasses while programming.

  5. #5
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924

    Default Just for fun...

    Here is how to read and write to a Serial EEPROM using SHIFTIN/SHIFTOUT.
    Using a 24FC1025.

    Why???? Why not???

    I have the DATA and CLOCK pins pulled up with 2.7k resistors.
    Follow the code with the data sheet to understand what is going on.
    Code:
    DEFINE OSC 20
    
    DPIN    VAR PORTB.2    'I2C DATA PIN
    CPIN    VAR PORTB.1    'I2C CLOCK PIN
    CONT1   CON %10100001  'READ CONTROL
    CONT0   CON %10100000  'WRITE CONTROL
    ADDR_HB   VAR BYTE
    ADDR_LB    VAR BYTE
    DATOW       VAR BYTE
    ACK            VAR BIT
    ADDR_HB = 0'%00000000
    ADDR_LB = 0'%00000000
    DATOW    VAR BYTE
    CNT VAR BYTE
    CNT = 0
    
    START:
        CNT = CNT + 1
        DATOW = 245
        GOSUB WRITE_DATA
        PAUSE 10
        GOSUB READ_DATA
        LCDOUT $FE,1,"TEST ",DEC CNT
        lcdout $FE,$C0,"DATA IN ",DEC DATI
        lcdout $FE,$90,"LB ",DEC ADDR_LB
        PAUSE 250
        GOTO START
        
        WRITE_DATA:     
        ADDR_LB = ADDR_LB + 1
        GOSUB START_ROM
        SHIFTOUT DPIN,CPIN,1,[CONT0]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTOUT DPIN,CPIN,1,[ADDR_HB]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTOUT DPIN,CPIN,1,[ADDR_LB]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTOUT DPIN,CPIN,1,[DATOW\8]      
        SHIFTOUT DPIN,CPIN,1,[%1\1]
        GOSUB STOP_ROM
        PAUSE 10
        RETURN
        
        READ_DATA: 
        GOSUB START_ROM
        SHIFTOUT DPIN,CPIN,1,[CONT0]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTOUT DPIN,CPIN,1,[ADDR_HB]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTOUT DPIN,CPIN,1,[ADDR_LB]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        GOSUB START_ROM
        SHIFTOUT DPIN,CPIN,1,[CONT1]
        SHIFTIN DPIN,CPIN,0,[ACK\1]
        SHIFTIN DPIN,CPIN,0,[DATI\8]
        SHIFTOUT DPIN,CPIN,1,[%1\1]
        GOSUB STOP_ROM
        PAUSE 10
        RETURN
        
        START_ROM:
        HIGH CPIN:HIGH DPIN:LOW DPIN:RETURN
        STOP_ROM:
        HIGH CPIN:LOW DPIN:HIGH DPIN:RETURN
    Make sure you have ANALOG turned off!!
    Dave
    Always wear safety glasses while programming.

  6. #6
    Join Date
    Mar 2010
    Location
    Minnesota, USA
    Posts
    41

    Default

    Thanks for the code guys! I will try it out on sunday when I get back.

  7. #7
    Join Date
    Mar 2010
    Location
    Minnesota, USA
    Posts
    41

    Default Mackrackit your code works :D

    Well I was able to get your code to work. I noticed when I was reading before using the I2CREAD I was getting all 255's and now I am reading using your code and still getting all 255's where ther is no data written so that is telling me that I was getting the I2CREAD to work before. I am now reading through all memory locations looking for the data I wrote to it before using the I2CWRITE command to try and figure out where it wrote it and why. Once this finishes I will post my findings and thoughts.

    Thanks again for the code.

    PS:
    I have not tried Dave's code yet

    UPDATE:
    I found the written data from my old code in Block 1 of the EEPROM. I am going to go back to the old code I had and try and make it work. I will post my findings
    Last edited by wolwil; - 25th April 2010 at 23:32.

  8. #8
    Join Date
    Mar 2010
    Location
    Minnesota, USA
    Posts
    41

    Thumbs up Finally got it to work!!!

    First and foremost Thank You, Thank You, Thank You for all of your help guys I really do appreciate it.

    Here is the working Code:
    Code:
    ' Define serial output pin
    SO      con     0 
    
    ' Define serial mode                          
    T2400   con     0                           
    
    ' 2 Byte Address Vars
    addr1   var     word                       
    addr2   var     word                       
    addr3   var     word                        
    
    ' Vars for data being written
    D1      Var     Byte                        
    D2      Var     Byte                      
    D3      Var     Byte                        
    
    ' Vars for data being read
    B1      VAR     BYTE                       
    B2      VAR     BYTE                       
    B3      VAR     BYTE                        
    
    ' Set Data Bytes
    D1 = 7                                      
    D2 = 6
    D3 = 5
    
    ' Set Address Bytes
    addr1 = 1
    addr2 = 2
    addr3 = 3
    
    I2CWRITE PORTB.1,PORTB.4,$A0,addr1,[D1]      ' Write a 1 to address 1
    PAUSE 10                                     ' Wait 10ms for write to complete
    I2CWRITE PORTB.1,PORTB.4,$A0,addr2,[D2]      ' Write a 2 to address 2
    PAUSE 10                                     ' Wait 10ms for write to complete
    I2CWRITE PORTB.1,PORTB.4,$A0,addr3,[D3]      ' Write a 3 to address 3
    PAUSE 10                                     ' Wait 10ms for write to complete
    
    I2CREAD PORTB.1,PORTB.4,$A0,addr1,[B1]      ' Read address 1 into B1
    I2CREAD PORTB.1,PORTB.4,$A0,addr2,[B2]      ' Read address 2 into B2
    I2CREAD PORTB.1,PORTB.4,$A0,addr3,[B3]      ' Read address 3 into B3
    
    Serout SO,T2400,["Addr",#addr1,":",#B1," and then Addr",#addr2,":",#B2," and then Addr",#addr3,":",#B3,13,10] ' Print B1's Value in DEC
    and it's out putting this to Hyperterm:
    Code:
    Addr1:7 and then Addr2:6 and then Addr3:5
    Addr1:7 and then Addr2:6 and then Addr3:5
    Addr1:7 and then Addr2:6 and then Addr3:5
    The problem I had in the beginning was I had the SDA/SCL Pins wrong and I did not have the A2 pin Tied to +5V but after correcting those I had my control byte misunderstood and thats why it would not work. After changing the control byte back to $A0 with the A2 held High and the propper pins chosen for SDA and SCL it now works like it should.

    I hope this thread saves everyone a ton of time in the future with these chips I know I sure learned a ton from this little experiance
    Last edited by wolwil; - 26th April 2010 at 00:58.

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts