I2C question

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
MarkW
Posts: 73
Joined: Fri Oct 27, 2006 8:09 pm

I2C question

Post by MarkW » Fri Feb 16, 2007 8:55 pm

I'm having a bit of a problem with the I2C routine. I recently wrote the code to manage data in a 24LC32 EEPROM in PicBasic Pro using a 16F684 and it works fine. This was for a new project and I thought this might be a good one to try my new Swordfish compiler on. So I started with the samples except I am using a 18F2321 PIC. Please see the code:

Device = 18F2321
Clock = 8
Config
OSC = INTIO1,
DEBUG = OFF,
MCLRE = OFF

// import libraries...
Include "I2C.bas"
Include "usart.bas"

// target 24LC32 I2C EEPROM device...
Const I2C_EEPROM = $A0

// local variables...
Dim
Value As String,
Address As Word,
Str As String(40)
{
****************************************************************************
* Name : WriteStr *
* Purpose : Write a string to I2C EEPROM - uses 2 byte address *
****************************************************************************
}

Sub WriteStr(pControl As Byte, pAddress As Word, pData As String)
Dim Index As Byte
Dim Ch As Char
I2C.Start
I2C.WriteByte(pControl)
I2C.WriteByte(pAddress.Byte1)
I2C.WriteByte(pAddress.Byte0)

Index = 0
Repeat
Ch = pData(Index)
Inc(Index)
I2C.WriteByte(Ch)
Until Ch = null
I2C.Stop
DelayMS(10)
End Sub

{
****************************************************************************
* Name : ReadStr *
* Purpose : Read a string from a I2C EEPROM - uses 2 byte address *
****************************************************************************
}
Sub ReadStr(pControl As Byte, pAddress As Word, ByRef pStr As String)
Dim index As Word
Dim Value As Char

I2C.Start
I2C.WriteByte(pControl)
I2C.WriteByte(pAddress.Byte1)
I2C.WriteByte(pAddress.Byte0)
I2C.Restart
I2C.WriteByte(pControl + 1)

index = 0
Value = I2C.ReadByte
While Value <> null
I2C.Acknowledge(I2C_ACKNOWLEDGE)
pStr(index) = Value
Inc(Index)
Value = I2C.ReadByte
Wend
pStr(Index) = null
I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
I2C.Stop
End Sub

'------------------ Main Program ------------------
// program start...
OSCCON = %01110000 'Set internal osc to 8 MHz
TRISA = %11111111
TRISB = %11111111
TRISC = %11111111

// Wait for osc to get stable
While OSCCON.2=0
Wend

Value = "Start"
USART.SetBaudrate(br9600)
USART.Write("Value = ", Value, 13, 10)

While true
// write a string, then read it back...
Address = 0
I2C.Initialize
WriteStr(I2C_EEPROM,Address,"This has been written to I2C EEPROM...")

Address = 0
ReadStr(I2C_EEPROM,Address,Str)

SetBaudrate(br9600)
USART.Write(Str, 13, 10)
DelayMS(1000)
Wend



What I get is the last 6 characters of the string - "ROM..."
If I change 'Address' above the Read statement to Address=1 I get "OM..." I never see any of the rest of the string that was supposed to be written to the EEPROM.

I'm not sure if Write isn't writing or the Read isn't reading correctly.
The EEPROM is a 24LC32 but the addressing looks the same as for a 24LC256 except for the extra MSB bits.

Please tell me what dumb thing I'm doing. The new project has a couple of I2C devices that I need to talk to and I would like to give Swordfish a try. (I'm using the full version - not SE).

Thanks,
Mark

Bruce
Posts: 16
Joined: Sun Oct 29, 2006 5:54 pm
Contact:

Post by Bruce » Sun Feb 18, 2007 4:17 pm

Hi Mark,

Have you tried this with an external osc? Just curious.

See if this thread doesn't help with internal osc setup & timing. It may be causing a problem if firing up at 1MHz, then taking a while to stabilize. http://www.sfcompiler.co.uk/forum/viewtopic.php?t=142

It runs & works as expected on an 18F452 with 24LC256 EEPROM. Sorry I don't have the particular parts you're using to test..!
Regards,

Bruce
http://www.rentron.com

MattH
Registered User
Registered User
Posts: 51
Joined: Mon Jan 01, 2007 8:03 pm
Location: Allentown, PA

Post by MattH » Sun Feb 18, 2007 10:11 pm

Hi Mark,

I tried the example (24LCDSTRING) using a 18F452-4MHz
and a X24C16P and got the same problem. The result was
always "ROM...".
After I switched to a 24LC256 it runs as expected. I have no clue what it is
but there must be a timing difference between eeprom manufacturers.

Matt

Bruce
Posts: 16
Joined: Sun Oct 29, 2006 5:54 pm
Contact:

Post by Bruce » Mon Feb 19, 2007 1:34 am

Check the data sheet for your EEPROM. If it's limited to 32 byte page writes, that would explain why it truncates your message.

Chop your message down to 32 bytes max. That will tell you immediately if that's the problem.
Regards,

Bruce
http://www.rentron.com

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Mon Feb 19, 2007 12:43 pm

I believe Bruce has identified why you are encountering problems with your I2C EEPROM. You will need to re-code for that particular device and take into account the limited page size.

If speed is not an issue, you can write on a byte by byte basis. For example,

Code: Select all

{
****************************************************************************
* Name    : WaitForWrite                                                   *
* Purpose : Wait until write sequence has completed                        *
****************************************************************************
}         
public sub WaitForWrite(pControl as byte)
   WaitForIdle
   Start
   WriteByte(pControl)
   WaitForIdle
   while NotAcknowledged 
      Restart
      WriteByte(pControl)
      WaitForIdle
   wend
   Stop
end sub
{
****************************************************************************
* Name    : WriteStr                                                       *
* Purpose : Write a string to I2C EEPROM - uses 2 byte address             *
****************************************************************************
}         
sub WriteStr(pControl as byte, pAddress as word, pData as string)

   dim Index as byte
   dim Ch as char
   
   Index = 0
   repeat
      Ch = pData(Index)

      I2C.Start
      I2C.WriteByte(pControl)
      I2C.WriteByte(pAddress.Byte1)
      I2C.WriteByte(pAddress.Byte0)
      I2C.WriteByte(Ch)
      I2C.Stop
   
      WaitForWrite(pControl)
      inc(Index)
      inc(pAddress)
   until Ch = null   
end sub
I've done some limited testing on a 24LC128 and the above works fine. I don't see why it would not work for your EEPROM device.

One think to note with the above is that it uses a 'WaitForWrite' sub. This has the advantage of not have a fixed write delay - for example, delayms(10) . So for non-page writes, it should be pretty quick...

MarkW
Posts: 73
Joined: Fri Oct 27, 2006 8:09 pm

Post by MarkW » Mon Feb 19, 2007 1:54 pm

Thanks everyone. The 32 byte page issue seems like a good bet. I still have the hardware on the breadboad and I will give the ideas a try later today. I'll post my findings. Thanks again.

MarkW
Posts: 73
Joined: Fri Oct 27, 2006 8:09 pm

Post by MarkW » Mon Feb 19, 2007 4:15 pm

The 32 byte page size was the problem. I took another look at the 24LC256 data sheet and it has a 64 byte page size. I did notice that I can write 31 bytes using the sample routines and not 32. It looks like sample adds a $0 at the end of the string which becomes the 32nd byte. Thanks to all. Mark

Post Reply