Shop OBEX P1 Docs P2 Docs Learn Events
EEPROM Writing Woes — Parallax Forums

EEPROM Writing Woes

Duane DegnDuane Degn Posts: 10,588
edited 2015-02-06 07:03 in Propeller 1
In an attempt to free up some hub RAM in my hexapod project. I'm trying to move PASM sections of objects into the EEPROM.

I used the ReadEEPROM and WriteEEPROM methods from the Eddie firmware but when I read back the data just written to the EEPROM, I get a lot of errors.

I switched from the PASM code to just some test data and found success or failure was heavily dependent on the data which was written.

Here's my test program.
DAT programName  byte "LoadToEeprom_150205e", 0  
CON

  _clkmode = xtal1 + pll16x
  _xinfreq = 5000000 

  CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
  MICROSECOND = CLK_FREQ / 1_000_000
  MILLISECOND = CLK_FREQ / 1_000

  I2C_CLOCK = 28
  I2C_DATA = 29

  DEBUG_BAUD = 115_200 

CON '' EEPROM Constants

  F32_EEPROM_START = $8000
  SERVO_EEPROM_START = $876C
  SERIAL_EEPROM_START = $8964
  EMPTY_EEPROM_START = SERIAL_EEPROM_START

CON

''     Parallax Serial Terminal
''    Control Character Constants

  CS = 16  ''CS: Clear Screen      
  CE = 11  ''CE: Clear to End of line     
  CB = 12  ''CB: Clear lines Below 

  HM =  1  ''HM: HoMe cursor       
  PC =  2  ''PC: Position Cursor in x,y          
  PX = 14  ''PX: Position cursor in X         
  PY = 15  ''PY: Position cursor in Y         

  NL = 13  ''NL: New Line        
  LF = 10  ''LF: Line Feed       
  ML =  3  ''ML: Move cursor Left          
  MR =  4  ''MR: Move cursor Right         
  MU =  5  ''MU: Move cursor Up          
  MD =  6  ''MD: Move cursor Down
  TB =  9  ''TB: TaB          
  BS =  8  ''BS: BackSpace          
           
  BP =  7  ''BP: BeeP speaker          

OBJ
 
  Com : "Parallax Serial Terminal"
  
PUB Main | first[3], last[3], size[3], eeprom[3]

  Com.Start(DEBUG_BAUD)                                           
  
  repeat
    NewLine
    Com.Str(string("Press any key to begin."))
    NewLine
    Com.Str(string("Warning, this program will write to the upper EEPROM."))
    waitcnt(clkfreq / 4 + cnt)
    result := Com.RxCount    
  until result

  Com.Char(CS)
  Com.Char(HM)
 
  waitcnt(clkfreq / 20 + cnt)

  NewLine
  Com.Str(string("WriteEEPROM($"))
  Com.Hex(@testData0, 8)
  Com.Str(string(", $"))
  Com.Hex(@testData0 + 511, 8)
  Com.Str(string(", $"))
  Com.Hex($9000, 8) 

  
  WriteEEPROM(@testData0, @testData0 + 511, $9000) 

  NewLine
  Com.Str(string("WriteEEPROM($"))
  Com.Hex(@testData1, 8)
  Com.Str(string(", $"))
  Com.Hex(@testData1 + 511, 8)
  Com.Str(string(", $"))
  Com.Hex($9200, 8) 

  
  WriteEEPROM(@testData1, @testData1 + 511, $9200) 

  NewLine
  Com.Str(string("WriteEEPROM($"))
  Com.Hex(@testData2, 8)
  Com.Str(string(", $"))
  Com.Hex(@testData2 + 511, 8)
  Com.Str(string(", $"))
  Com.Hex($9400, 8) 

  
  WriteEEPROM(@testData2, @testData2 + 511, $9400) 

  NewLine
  NewLine
  Com.Str(string("Press any key to continue."))
  repeat
    waitcnt(clkfreq / 4 + cnt)
    result := Com.RxCount   
  while result == -1

  CompareLongs(@testData0, $9000, 128)
  CompareLongs(@testData1, $9200, 128)
  CompareLongs(@testData2, $9400, 128)
  
  Com.Str(string("End of program."))

  repeat
   
PUB CompareLongs(localPtr, eepromPtr, localSize) | localLong, rowCount

  rowCount := 0
  NewLine
  Com.Str(string("Comparing RAM with EEPROM."))
  NewLine
  Com.Str(string("RAM address = $"))
  Com.Hex(localPtr, 8)
  NewLine
  Com.Str(string("EEPROM address = $"))
  Com.Hex(eepromPtr, 8)
  NewLine
  Com.Str(string("Longs to compare = $"))
  Com.Hex(localSize, 8)
  NewLine
  
  repeat localSize
    ifnot rowCount++ // 4
      NewLine
      Com.Str(string("<$"))
      Com.Hex(localPtr, 4)
      Com.Str(string("&$"))
      Com.Hex(eepromPtr, 4)
      Com.Str(string(">"))
  
    ReadEEPROM(@localLong, @localLong + 3, eepromPtr)
    Com.Str(string("|$"))
    Com.Hex(long[localPtr], 8)
    if long[localPtr] == localLong
      Com.Str(string("==$"))
    else
      Com.Str(string(7, "<>$"))
      result++
    Com.Hex(localLong, 8)  
    localPtr += 4
    eepromPtr += 4

  NewLine
  Com.Str(string("The compare method found "))
  Com.Dec(result)
  Com.Str(string(" unmatched longs."))
  NewLine 
  if result
    Com.Str(string(7, " Failure!!! ", 7))
  else
    Com.Str(string(" Success!!! "))

PRI NewLine                                        '' Called from DebugCog
'' Clear the end of the current line and then
'' start a new line.

  Com.Char(CE)
  Com.Char(13)
  result := 1

PUB FindString(firstStr, stringIndex)      '' Called from DebugCog
'' Finds start address of one string in a list
'' of string. "firstStr" is the address of 
'' string #0 in the list. "stringIndex"
'' indicates which of the strings in the list
'' the method is to find.
'' Version from HexapodRemote140128a
'' Version Hexapod140129a, removed commented
'' out code.

  result := firstStr 
  repeat while stringIndex    
    repeat while byte[result++]  
    stringIndex--

CON

  SDA = I2C_DATA
  SCL = I2C_CLOCK
  ' EEPROM constants
  I2C_ACK       = 0
  I2C_NACK      = 1
  DEVICE_CODE   = %0110 << 4
  PAGE_SIZE     = 128
  
PRI ReadEEPROM(startAddr, endAddr, eeStart) | addr

  ''Copy from EEPROM beginning at eeStart address to startAddr..endAddr in main RAM.
  
  SetAddr(eeStart)                                      ' Set EEPROM's address pointer 
  i2cstart
  SendByte(%10100001)                                   ' EEPROM I2C address + read operation
  if startAddr == endAddr
    addr := startAddr
  else
    repeat addr from startAddr to endAddr - 1           ' Main RAM index startAddr to endAddr
      byte[addr] := GetByte                             ' GetByte byte from EEPROM & copy to RAM 
      SendAck(I2C_ACK)                                  ' Acknowledge byte received
  byte[addr] := GetByte                                 ' GetByte byte from EEPROM & copy to RAM 
  SendAck(I2C_NACK)
  i2cstop                                               ' Stop sequential read
  
PRI WriteEEPROM(startAddr, endAddr, eeStart) | addr, page, eeAddr

  ''Copy startAddr..endAddr from main RAM to EEPROM beginning at eeStart address.

  addr := startAddr                                     ' Initialize main RAM index
  eeAddr := eeStart                                     ' Initialize EEPROM index
  repeat
    page := addr +PAGE_SIZE -eeAddr // PAGE_SIZE <# endaddr +1 ' Find next EEPROM page boundary
    SetAddr(eeAddr)                                     ' Give EEPROM starting address
    repeat                                              ' Bytes -> EEPROM until page boundary
      SendByte(byte[addr++])
    until addr == page
    i2cstop                                             ' From 24LC256's page buffer -> EEPROM
    eeaddr := addr - startAddr + eeStart                ' Next EEPROM starting address
  until addr > endAddr                                  ' Quit when RAM index > end address

PRI SetAddr(addr) : ackbit

  'Sets EEPROM internal address pointer.

  ' Poll until acknowledge.  This is especially important if the 24LC256 is copying from buffer to EEPROM.
  ackbit~~                                              ' Make acknowledge 1
  repeat                                                ' Send/check acknowledge loop
    i2cstart                                            ' Send I2C start condition
    ackbit := SendByte(%10100000)                       ' Write command with EEPROM's address
  while ackbit                                          ' Repeat while acknowledge is not 0

  SendByte(addr >> 8)                                   ' Send address high byte
  SendByte(addr)                                        ' Send address low byte

PRI I2cStart

  ' I2C start condition.  SDA transitions from high to low while the clock is high.
  ' SCL does not have the pullup resistor called for in the I2C protocol, so it has to be
  ' set high. (It can't just be set to inSendByte because the resistor won't pull it up.)

  dira[SCL]~                                            ' SCL pin outSendByte-high
  dira[SDA]~                                            ' Let pulled up SDA pin go high
  dira[SDA]~~                                           ' SDA -> outSendByte for SendByte method

PRI I2cStop

  ' Send I2C stop condition.  SCL must be high as SDA transitions from low to high.
  ' See note in i2cStart about SCL line.

  dira[SDA]~~
  dira[SCL]~                                            ' SCL -> high
  dira[SDA]~                                            ' SDA -> inSendByte GetBytes pulled up
  
PRI SendAck(ackbit)

  ' Transmit an acknowledgment bit (ackbit).

  dira[SDA] := !ackbit                                  ' Set SDA output state to ackbit
  dira[SDA]~~                                           ' Make sure SDA is an output
  dira[SCL]~                                            ' Send a pulse on SCL
  dira[SCL]~~
  dira[SDA]~                                            ' Let go of SDA

PRI GetAck : ackbit

  ' GetByte and return acknowledge bit transmitted by EEPROM after it receives a byte.
  ' 0 = I2C_ACK, 1 = I2C_NACK.

  dira[SDA]~                                            ' SDA -> SendByte so 24LC256 controls
  dira[SCL]~                                            ' Start a pulse on SCL
  ackbit := ina[SDA]                                    ' GetByte the SDA state from 24LC256
  dira[SCL]~~                                           ' Finish SCL pulse
  dira[SDA]~~                                           ' SDA -> outSendByte, master controls
  
PRI SendByte(b) : ackbit | i

  ' Shift a byte to EEPROM, MSB first.  Return if EEPROM acknowledged.  Returns
  ' acknowledge bit.  0 = I2C_ACK, 1 = I2C_NACK.
  'waitcnt(800000 + cnt)
  
  b ><= 8                                               ' Reverse bits for shifting MSB right
  dira[SCL]~~                                           ' SCL low, SDA can change
  repeat 8                                              ' 8 reps sends 8 bits
    'waitcnt(80000 + cnt)
    dira[SDA] := !b                                     ' Lowest bit sets state of SDA
    'waitcnt(80000 + cnt)
    dira[SCL]~                                          ' Pulse the SCL line
    'waitcnt(80000 + cnt)
    dira[SCL]~~
    
    b >>= 1                                             ' Shift b right for next bit
  ackbit := GetAck                                      ' Call GetByteAck and return EEPROM's Ack

PRI GetByte : value

  ' Shift in a byte, MSB first.  
  'waitcnt(800000 + cnt)
  value~                                                ' Clear value
  dira[SDA]~                                            ' SDA input so 24LC256 can control
  repeat 8                                              ' Repeat shift in eight times
    'waitcnt(80000 + cnt)
    dira[SCL]~                                          ' Start an SCL pulse
    value <-= 1                                         ' Shift the value left
    'waitcnt(80000 + cnt)
    value |= ina[SDA]                                   ' Add the next most significant bit
    dira[SCL]~~                                         ' Finish the SCL pulse
    
DAT

testData0     long 0[128]
testData1     long -1[128]
testData2     long $AA55A55A[128]

The output from "testData1" and "testData2" always matches but I consistently get 34 errors when comparing "testData0" with what is read back from EEPROM. Here's the output for "testData0".
Comparing RAM with EEPROM.
RAM address = $00000064
EEPROM address = $00009000
Longs to compare = $00000080

<$0064&$9000>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0074&$9010>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0084&$9020>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0094&$9030>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00A4&$9040>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00B4&$9050>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00C4&$9060>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00D4&$9070>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00E4&$9080>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$00F4&$9090>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0104&$90A0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0114&$90B0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0124&$90C0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0134&$90D0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0144&$90E0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0154&$90F0>|$00000000==$00000000|$00000000<>$FFFFFF03|$00000000==$00000000|$00000000<>$FFFFFF03
<$0164&$9100>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0174&$9110>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0184&$9120>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0194&$9130>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01A4&$9140>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01B4&$9150>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01C4&$9160>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01D4&$9170>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01E4&$9180>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$01F4&$9190>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0204&$91A0>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0214&$91B0>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0224&$91C0>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0234&$91D0>|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000|$00000000==$00000000
<$0244&$91E0>|$00000000==$00000000|$00000000<>$FFFFFFFF|$00000000==$00000000|$00000000==$00000000
<$0254&$91F0>|$00000000==$00000000|$00000000==$00000000|$00000000<>$FFFFFFFF|$00000000==$00000000
The compare method found 34 unmatched longs.
 Failure!!!

I'm pretty sure there are other values besides zero which will cause this error, but since the error occurs so consistently with zero data values, I'm inclined to think the EEPROM requires more power to write a zero bit than to write a one bit.

I've seen similar issues when using SRAM and found certain data value would cause an error while other data values didn't cause trouble. Based on my previous experience, I think the decoupling cap on the EEPROM might be inadequate but I'm not sure. The boards program correctly so obviously the EEPROM can be written to.

I may try actively driving the clock line instead of relying on the pull-up resistor.

I've tried this code on two different QuickStart boards with the same results.

I've commented out the delays I've tried. The delays didn't help.

Do any of you see anything wrong with the I2C methods?
PRI SendByte(b) : ackbit | i

  ' Shift a byte to EEPROM, MSB first.  Return if EEPROM acknowledged.  Returns
  ' acknowledge bit.  0 = I2C_ACK, 1 = I2C_NACK.
  'waitcnt(800000 + cnt)
  
  b ><= 8                                               ' Reverse bits for shifting MSB right
  dira[SCL]~~                                           ' SCL low, SDA can change
  repeat 8                                              ' 8 reps sends 8 bits
    'waitcnt(80000 + cnt)
    dira[SDA] := !b                                     ' Lowest bit sets state of SDA
    'waitcnt(80000 + cnt)
    dira[SCL]~                                          ' Pulse the SCL line
    'waitcnt(80000 + cnt)
    dira[SCL]~~
    
    b >>= 1                                             ' Shift b right for next bit
  ackbit := GetAck                                      ' Call GetByteAck and return EEPROM's Ack

PRI GetByte : value

  ' Shift in a byte, MSB first.  
  'waitcnt(800000 + cnt)
  value~                                                ' Clear value
  dira[SDA]~                                            ' SDA input so 24LC256 can control
  repeat 8                                              ' Repeat shift in eight times
    'waitcnt(80000 + cnt)
    dira[SCL]~                                          ' Start an SCL pulse
    value <-= 1                                         ' Shift the value left
    'waitcnt(80000 + cnt)
    value |= ina[SDA]                                   ' Add the next most significant bit
    dira[SCL]~~                                         ' Finish the SCL pulse
    

Comments

  • Tracy AllenTracy Allen Posts: 6,664
    edited 2015-02-05 18:00
    Duane, I think it lacks a delay in the WriteEEPROM method, after sending the stop bit for each page. The eeprom takes about 5ms to complete a write. You may be able to poll for ready/notReady (ACK/NACK).
  • ChrisGaddChrisGadd Posts: 310
    edited 2015-02-05 19:23
    I get the same results as you do, so I find it unlikely to be anything to do with components.

    It's writing just fine; my EEPROM reader reads all 00's at $9000, FF's at $9200, and $5A A5s at $9400. That's using a Spin-based I2C object with 10K pullups on SCL and SDA, as well as other I2C devices on the bus.

    It looks like there's a problem with the reader; I'm not quite sure what's going on, but here's the I2C traffic for the first dozen bytes of the read.
    https://www.dropbox.com/s/a90uax1ef8ly4bo/I2C%20traffic.jpg?dl=0

    Also the EEPROM reader object I used: https://www.dropbox.com/s/hkzihvu9bwyr36d/EEPROM%20Duane%20test%20-%20Archive.zip?dl=0

    @Tracy, the SetAddr method does poll for an ack.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-02-05 19:49
    ChrisGadd wrote: »
    It's writing just fine; my EEPROM reader reads all 00's at $9000, FF's at $9200, and $5A A5s at $9400.k.

    That's good to know.

    I'll take a look at your reader to see if it behaves better than the one I'm using.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-05 20:02
    Your code is doing the right thing when it issues an address in that it sits in a loop until it receives an ack. However try putting in that 5ms delay as well and you really only need to do that after every page write (normally 64 bytes) rather than the slow old byte by byte method.

    You can use my Hardware Explorer to confirm your EEPROM and hardware is operating correctly although my I2C routines drive the SCL line high and low rather than just open-drain as the latter method assumes that something else will pull the SCL line as well, which is for all practical purposes never the case. For your code which open-drains the SCL line the 10K pullup is too light given line length and capacitance etc. This 10K value is only good for a device or two in close proximity to the EEPROM and there is no reason whatsoever to not have a much lower value of 2K2 for both.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-02-05 20:20
    The "Propeller Eeprom" object from the PEK lessons reads the data correctly.

    I had previously used "Propeller Eeprom" but switched to the Eddie code since I had been working with the Eddie firmware a lot lately. I hadn't tested the EEPROM code on the Eddie firmware so it's good to know it has a problem. I'll make sure and fix the EEPROM code with the next update to the Eddie firmware.

    I was surprised to learn one of my QuickStart boards didn't have a pull-up on the clock. That's a handy check Chris.

    Thanks for everyone's help.

    I still don't know what was wrong with the original code but I have a working solution so I'm not very concerned about finding the error. This issue has already cost me more time than I'd like so I don't think I'll hunt down the exact problem.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2015-02-05 22:38
    Duane Degn wrote:
    I was surprised to learn one of my QuickStart boards didn't have a pull-up on the clock.
    Do any of Parallax's boards have a pullup on SCL?* For EEPROMs, it's not a requirement, unless you're toggling SCL with DIRA instead of OUTA. The only time it's really necessary from a hardware standpoint is when there's a device on the bus that uses clock stretching to create a HOLD state.

    -Phil

    * Okay, I know the Spinneret does, and the Prop Backpack does/did/will. 'Not sure it's the usual case, though.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-06 00:20
    Do any of Parallax's boards have a pullup on SCL?* For EEPROMs, it's not a requirement, unless you're toggling SCL with DIRA instead of OUTA. The only time it's really necessary from a hardware standpoint is when there's a device on the bus that uses clock stretching to create a HOLD state.

    -Phil

    * Okay, I know the Spinneret does, and the Prop Backpack does/did/will. 'Not sure it's the usual case, though.

    The funny thing is that there are some drivers that try to adhere to the standard as they understand it but in trying to implement this accommodation for clock stretching and also multi-master arbitration that it is also incomplete in that this needs to be supported at the bit by bit level, which is easy in hardware, but a pain in software. However, for all practical purposes requesting clock stretching is not implemented in I2C chips nor is multi-master, but these had use in the early days of I2C with slow CPUs etc.Then again it really complicates things by introducing state machine levels of exceptions etc, you don't want to go there, or need to really.

    My best advice to anyone is use a pullup for SCL if you want, it won't hurt, but just drive the clock line normally as you won't have any problems and it will be able to compensate for bus loading and capacitance, even at high speeds.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-02-06 05:50
    Do any of Parallax's boards have a pullup on SCL?* For EEPROMs,

    I don't have all the Propeller boards Parallax has made but I think it's safe to say most of their boards have pull-ups on both lines.

    The only exceptions I'm aware of are the Propeller Demo Board and the Propeller Professional Development Board.

    Most of the 3rd party boards I'm aware of have the second pull-up.

    BTW, my hexapod now has additional free RAM. I was successful in moving the PASM sections of the servo32 object and F32 to the EEPROM. The buffer used to temporarily hold the PASM code is reused as stack space for cogs using Spin. Pretty cool IMO.
  • Hal AlbachHal Albach Posts: 747
    edited 2015-02-06 06:13
    Do any of Parallax's boards have a pullup on SCL?* For EEPROMs, it's not a requirement, unless you're toggling SCL with DIRA instead of OUTA. The only time it's really necessary from a hardware standpoint is when there's a device on the bus that uses clock stretching to create a HOLD state.

    -Phil

    * Okay, I know the Spinneret does, and the Prop Backpack does/did/will. 'Not sure it's the usual case, though.

    Just checked the Schematics of the Project Board USB and Activity Board (both rev A) and they both have 10K pullups to 3.3V on SDA and SCL. The project board uses two SMD resistors immediately to the right of the EEPROM and the Activity Board uses a very tiny 10K four pack just above the EEPROM.
  • ChrisGaddChrisGadd Posts: 310
    edited 2015-02-06 06:50
    Yeah, the SDA and SCL detection sometimes gltiches, dunno why.

    I have however discovered the problem in your EEPROM reader; it's not so much a question of why the 00's were sometimes misreading as why the others were reading correctly.
    PRI SendAck(ackbit)
    
      ' Transmit an acknowledgment bit (ackbit).
    
      dira[SDA] := !ackbit                                  ' Set SDA output state to ackbit
    [color=red]  dira[SDA]~~                                           ' Make sure SDA is an output[/color]
      dira[SCL]~                                            ' Send a pulse on SCL
      dira[SCL]~~
      dira[SDA]~                                            ' Let go of SDA
    
    With that red line, the object can only send ACKs, the NAK is never being sent at the end of each read of four bytes. The EEPROM therefore interprets the following start, write-address, restart, and read-address all as being requests for more bytes.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-02-06 07:03
    ChrisGadd wrote: »
    With that red line, the object can only send ACKs, the NAK is never being sent at the end of each read of four bytes. The EEPROM therefore interprets the following start, write-address, restart, and read-address all as being requests for more bytes.

    Very good. Thanks for finding that.

    BTW, your detection didn't glitch; the pull-up on the clock line wasn't soldered properly on my QuickStart. I don't know if it was a defect from Parallax or if I did something to damage the board. I'm glad to know the board has a missing pull-up, I had been using it to test an I2C device. I'm sure your detection code saved me a bunch of time.
Sign In or Register to comment.