Menu

Trouble with Kent's I2C Eeprom routine

Help
Anonymous
2013-10-02
2013-10-04
  • Anonymous

    Anonymous - 2013-10-02

    Hello all,

    Per Kent's advice, this is a new but related thread on his eeprom routine. Here's the set-up. I have a toggle switch on A.0. In one position, reading from the 24LC256 is demoed, in the other position writing to the chip is demoed (always after a restart power-up).

    The results appear on serial terminal software. When writing to the eeprom, I have the terminal software send one character at a time, with a 50 mS pause between each.

    Here's the trouble: reading the eeprom always works, but writing to it always sends the same garbage. I had previously done a similar project with similar source code on a PICAXE which worked flawlessly. Here's my GC Basic code. I hope it formats halfway decently on this forum:

    ;A program to send and receive text to and from the
    ;24LC256 eeprom using software I2C routines.

    ;----- Configuration

    #chip 16F88, 8 ;PIC16F88 running at 8 MHz
    #config mclr=off ;reset handled internally
    #config osc=int ;use internal clock
    #include <I2CEeprom.h> ;Kent's header file

    ;----- Constants

    #define sw PortA.0 ;toggle switch on pin 17
    #define SerOutPort PortA.3 ;serial output on pin 2
    #define SerInPort PortA.4 ;serial input on pin 3
    #define SendAHigh Set SerOutPort on ;output logic levels
    #define SendALow Set SerOutPort off
    #define RecAHigh SerInPort on ;input logic levels
    #define RecALow SerInPort off

    #define SDA PortB.0 ;data on pin 6
    #define SCL PortB.1 ;clock on pin 7
    #define waittime 1 ms
    #define chipwrite b'10100000' ;I2C address 000
    #define chipread b'10100001'

    #define eof 0xff ;end of file marker

    ;----- Variables

    dim msb, lsb, datum as byte
    dim address as word alias msb, lsb

    ;----- Program

    dir PortA 0b11110111

    InitSer 1, r2400, 1+WaitForStart, 8, 1, none, invert

    if sw = 0 then ;read eeprom
    address = 0 ;prime the loop
    datum = eeprom_receive(msb, lsb)

    do while datum <> eof               ;quit if end of file
      serSend 1, datum                  ;else send to terminal
      address ++                        ;set for the next byte
      datum = eeprom_receive(msb, lsb)
    loop
    

    else ;write to eeprom
    serReceive 1, datum ;get first datum
    address = 0

    do while datum <> eof
      eeprom_send(msb, lsb, datum)
      wait 10 mS  
      address ++                        ;point to next address
      serReceive 1, datum               ;get next datum
    loop
    
    eeprom_send(msb, lsb, eof)          ;append eof marker
    

    end if


    Thanks, Thomas Henry

     
  • Anobium

    Anobium - 2013-10-02

    Kent - This looks like the same issue that I am currently re. Does this circuit have pulls up on the I2C lines? If so, then the new code may resolve this issue. If not, ignore this comment.

     
    • Anonymous

      Anonymous - 2013-10-02

      Yes, I should have mentioned it. I do have 4.7k pull-ups on both lines.

      Thomas Henry

       
  • kent_twt4

    kent_twt4 - 2013-10-03

    Thomas et al thanks for starting another thread, since we are talking about my old software I2C header file, as opposed to the GCBasic inbuilt routines. Things can get confusing in a hurry.

    It's been quite awhile since I've played with the soft I2C. Also, couldn't find by Olimex Pic-P18 board, so the Pic-P40 and a 16f877A chip will have to do for my example. Even lost my soft I2C with pullup header file, good reason to share on the forum :).

    Had trouble with the SerSend, so you get a double dose with a soft USART routine also, set for 9600 Buad. No internal osc with the 16f877A, so the OSC is 20MHZ crystal.

    The original soft I2C header seems just fine. My trouble was with the SerSend, so here is my working example. No serial receive going on, just write some numbers, then read back every 30 sec on the terminal.

    Let me know if any questions, I notice there was no include? in your posted code.

    #chip 16f877A,20
    #config OSC=HS
    
    #include <I2CMstrSoftPullup.h> 'Or whatever you want to call it
    #define SDA PortC.4            '16f877A
    #define SCL PortC.3            '16f877A
    #define waittime 1 ms
    #define chipwrite b'10100000'  '24lc256 address 1010+A2A1A0+R/W
    #define chipread b'10100001'
    Dim address as Word
    
    'InitSer 1, r2400, 1+WaitForStart, 8, 1, none, normal
    '#define SerOutPort PortB.1 ;serial output on pin 2
    '#define SerInPort PortB.0 ;serial input on pin 3
    '#define SendAHigh Set SerOutPort on ;output logic levels
    '#define SendALow Set SerOutPort off
    '#define RecAHigh SerInPort on ;input logic levels
    '#define RecALow SerInPort off
    'dir SerInPort in
    Call Ser_Init
    
    address = 0
    For logtemp = 0 to 255
        address = address + 1
        addrl = address
        addrh = address_h
        eeprom_send(addrh, addrl, logtemp)
        wait 10 ms   'Need some delay here for proper operation
        'SerSend 1, logtemp
        bin2ascii logtemp
        Xmit_RS232 10:Xmit_RS232 13  ;line feed, carriage return
    Next
    wait 30 s
    
    Main:
    Do
    address = 0
    For logtempA = 0 to 255
        address = address + 1
        addrl = address
        addrh = address_h
        eepromA = eeprom_receive(addrh,addrl)
        wait 10 ms
        'SerSend 1, eepromA
        bin2ascii eepromA
        Xmit_RS232 10:Xmit_RS232 13  ;line feed, carriage return
    
    Next
    wait 30 s
    Loop
    goto Main
    
    Sub Ser_Init
    ;slight adjustment was required for 9600bps delay value
    #define baud 103
    #define halfbaud 52 ;place Read of SerRx in middle of bit
    #define SerTxHigh Set PortB.1 On
    #define SerTxLow Set PortB.1 Off
    #define SerRx PortB.0
    dir PortB.1 out ;Tx
    dir PortB.0 in ;Rx
    SerTxHigh ;Initial RS232 idle state
    end sub
    
    Sub RCV_RS232 
    RxWait:
    IF SerRx On Then goto RCV_RS232 ;wait for start bit
    wait halfbaud us ;do half bit time delay
    If SerRx On Then goto RxWait
    RxByte = 0
    For RxBit = 1 to 8 ;set up to read 8 bits
    wait baud us
    Rotate RxByte Right
    If SerRx On then Set RxByte.7 1
    If SerRx Off Then Set RxByte.7 0
    Next
    wait baud us
    End sub
    
    sub XMIT_PRINT (PrintData$)
    PrintLen = PrintData(0)
    if PrintLen = 0 then exit sub
    'Write Data
    for SysPrintTemp = 1 to PrintLen
    XMIT_RS232(PrintData(SysPrintTemp))
    next
    end sub
    
    Sub XMIT_RS232(Xmit_Byte)#NR
    SerTxLow
    wait baud us
    For cntr = 1 to 8
    Rotate Xmit_Byte Right
    If Status.C ON Then SerTxHigh
    If Status.C Off Then SerTxLow
    wait baud us
    Next
    SerTxHigh
    wait baud us
    end sub
    
    sub bin2ascii (LCDValue) #NR
    LCDValueTemp = 0
    LCDShowChar = 0
    SERCEN = 0
    SERDEC = 0
    SERUN = 0
    
    If LCDValue >= 100 then
    LCDValueTemp = LCDValue / 100 
    LCDValue = SysCalcTempX
    SERCEN = LCDValueTemp + 48
    Xmit_RS232 (SERCEN)
    LCDShowChar = TRUE
    End If
    
    If LCDShowChar > 0 or LCDValue >= 10 then
    LCDValueTemp = LCDValue / 10 
    LCDValue = SysCalcTempX
    SERDEC = LCDValueTemp + 48
    Xmit_RS232 (SERDEC)
    End If
    
    SERUN = LCDValue + 48
    Xmit_RS232 (SERUN)
    End Sub
    
    sub bin2ascii (LCDValue as word ) #NR
    Dim SysCalcTempX As Word
    LCDValueTemp = 0
    LCDShowChar = 0
    SERDECMIL = 0
    SERMIL = 0
    SERCEN = 0
    SERDEC = 0
    SERUN = 0
    
    If LCDValue >= 10000 then
    LCDValueTemp = LCDValue / 10000 [word]
    LCDValue = SysCalcTempX
    SERDECMIL = LCDValueTemp + 48
    Xmit_RS232 (SERDECMIL)
    LCDShowChar = TRUE
    End If
    
    If LCDShowChar > 0 or LCDValue >= 1000 then
    LCDValueTemp = LCDValue / 1000 [word]
    LCDValue = SysCalcTempX
    SERMIL = LCDValueTemp + 48
    Xmit_RS232 (SERMIL)
    LCDShowChar = TRUE
    End If
    
    If LCDShowChar > 0 or LCDValue >= 100 then
    LCDValueTemp = LCDValue / 100 [word]
    LCDValue = SysCalcTempX
    SERCEN = LCDValueTemp + 48
    Xmit_RS232 (SERCEN)
    LCDShowChar = TRUE
    End If
    
    If LCDShowChar > 0 or LCDValue >= 10 then
    LCDValueTemp = LCDValue / 10 [word]
    LCDValue = SysCalcTempX
    SERDEC = LCDValueTemp + 48
    Xmit_RS232 (SERDEC)
    End If
    
    SERUN = LCDValue + 48
    Xmit_RS232 (SERUN)
    End Sub
    
     
  • Anonymous

    Anonymous - 2013-10-03

    Thank you, Kent. I'll give it a whirl as soon as I can get my decrepit workbench laptop up and running (I hope yet tonight).

    The Include is indeed in my file, but disappeared on the Forum posting. Just what is the secret of making code look right, including the comments, spaces and font?

    Thanks again, so much for dipping into this.

    Thomas Henry

     
  • kent_twt4

    kent_twt4 - 2013-10-03

    The Formatting Help button has the answer, been mentioned before, use the tilde's being sure their is a blank line before and after too.

    "~~~~"
    code here
    "~~~~"

    So without the exclamations:

    code here
    

    Check preview, and should be good to go now.

     
  • Anonymous

    Anonymous - 2013-10-04

    Hi Kent,

    Well, you're right. The original header file code seems to be fine. I changed my experiment so that rather than getting the text to be written to the eeprom from the serial port, I get it from an internal string and send it one character at a time.

    In a nutshell, either the software serial stuff is troublesome, or there's an unexpected interaction between your I2C eeprom code and the GC Basic software serial routines.

    I'll have to rethink how I'm going to handle this, but at least I now know that it is possible to reliably read and write to the 24LC256 on its own.

    Thanks again for your good work.

    Thomas Henry

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.