I2C again

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 again

Post by MarkW » Wed Feb 21, 2007 4:26 pm

My previous post cleared up one problem (Thanks again everybody) but I have another. My task is to write 13 byte arrays to an EEPROM and recover them. I have used the example routines with modification to accept a byte array insted of a char array. It almost works except for a problem I can't figure out.

The write portion seems to work OK.

The read portion works as long as I explicitly set the EEPROM starting address at each read - which will not be practical in the actual application.

If I try to put the read operation in a loop something odd happens to the EEPROM address as the loop executes. See the notes in the code example. It looks like something in the ReadStr() code is altering the address word. Comment out the ReadStr() line and the address will display correctly.

The address should show $00 $10 $20 $30 but it shows $00 $01 $01 $01 and the data that is actually read from the EEPROM is the data at those addresses.

Any ideas?

Thanks,
Mark






{
****************************************************************
* Name : I2C_Test.BAS *
* Author : M. Whatley *
* Notice : Copyright (c) 2007 Complete Inc *
* : All Rights Reserved *
* Date : 2/21/2007 *
* Version : 1.0 *
* Notes : Test program - I2C access *
* : *
****************************************************************
}
Device = 18F2321
Clock = 8
Config
OSC = INTIO1,
DEBUG = OFF,
MCLRE = OFF

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

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

{
****************************************************************************
* Name : WriteStr *
* Purpose : Write a string to I2C EEPROM - uses 2 byte address *
****************************************************************************
}
Sub WriteStr(pControl As Byte, pAddress As Word, ByRef pData() As Byte)
Dim Index As Byte
Dim Ch As Byte
I2C.Start
I2C.WriteByte(pControl)
I2C.WriteByte(pAddress.Byte1)
I2C.WriteByte(pAddress.Byte0)

Index = 0
While index < 13
Ch = pData(Index)
Inc(Index)
I2C.WriteByte(Ch)
Wend
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, ByRef pAddress As Word, ByRef pStr() As Byte)
Dim index As Word
Dim Value As Byte

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 index < 13
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 +++++++++++++++++++++++++++
// local variables...
Dim bytData(13) As Byte
Dim bytRX(13) As Byte
Dim wrdAddress As Word
Dim i As Byte
Dim j As Byte
Dim wrdEadr As Word

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

MainLoop:
'Add some dummy data to use
bytData(0) = 1
bytData(1) = 2
bytData(2) = 3
bytData(3) = 4
bytData(4) = 5
bytData(5) = 6
bytData(6) = 7
bytData(7) = 8
bytData(8) = 9
bytData(9) = 10
bytData(10) = 11
bytData(11) = 12
bytData(12) = 00

SetBaudrate(br9600)
USART.Write("Write", 13, 10)

'Write ten 13 byte arrays into the EEPROM. Each array to start at a 16 byte
'address boundry starting at address $00
'This seems to work as expected.
I2C.Initialize
wrdAddress = 0
For i = 1 To 10
WriteStr(I2C_EEPROM,wrdAddress,bytData)
bytData(12) = bytData(12) + 1
wrdAddress = wrdAddress + 16
Next

SetBaudrate(br9600)
USART.Write("Read", 13, 10)

'Now read the first four arrays. Set the address before each read.
'This works as expected
wrdAddress = 0 '<------Set the address
USART.Write(HexToStr(wrdAddress,4,"0"), ":")
ReadStr(I2C_EEPROM,wrdAddress, bytRX) 'Read array at address
SetBaudrate(br9600) 'Display the array
For j = 0 To 12
USART.Write(HexToStr(bytRX(j),2,"0"),"-")
Next
USART.Write(13,10)

wrdAddress = 16 '<------Set the address
USART.Write(HexToStr(wrdAddress,4,"0"), ":")
ReadStr(I2C_EEPROM,wrdAddress, bytRX) 'Read array at address
SetBaudrate(br9600) 'Display the array
For j = 0 To 12
USART.Write(HexToStr(bytRX(j),2,"0"),"-")
Next
USART.Write(13,10)

wrdAddress = 32 '<------Set the address
USART.Write(HexToStr(wrdAddress,4,"0"), ":")
ReadStr(I2C_EEPROM,wrdAddress, bytRX) 'Read array at address
SetBaudrate(br9600) 'Display the array
For j = 0 To 12
USART.Write(HexToStr(bytRX(j),2,"0"),"-")
Next
USART.Write(13,10)

wrdAddress = 48 '<------Set the address
USART.Write(HexToStr(wrdAddress,4,"0"), ":")
ReadStr(I2C_EEPROM,wrdAddress, bytRX) 'Read array at address
SetBaudrate(br9600) 'Display the array
For j = 0 To 12
USART.Write(HexToStr(bytRX(j),2,"0"),"-")
Next

USART.Write(13,10)
USART.Write(13,10)
USART.Write(13,10)


'Now lets try to read the first four arrays using a different method...
'For some reason wrdAddress equals 0 on the first pass and 16 on the second
'pass but the 3rd and 4th passes show wrdAddress = $01

wrdAddress = 0
For i = 1 To 4

USART.Write(HexToStr(wrdAddress,4,"0"), ":") 'show the address

'Comment out the next line and wrdAddress will show the correct value each time
ReadStr(I2C_EEPROM,wrdAddress, bytRX) 'Read array at address

SetBaudrate(br9600) 'Display the array
For j = 0 To 12
USART.Write(HexToStr(bytRX(j),2,"0"),"-")
Next
USART.Write(13,10)

wrdAddress = wrdAddress + 16 'set the next address

Next
DelayMS(1000)

GoTo Mainloop

End

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 » Wed Feb 21, 2007 5:03 pm

In your program you have dimensioned your RX array as

dim bytRX(13) as byte

which gives you 0..12 elements

you then call ReadStr(I2C_EEPROM,wrdAddress, bytRX)

in your routine you have

while index < 13
...
inc(Index)
wend

which will loop 0..12. You then have

pStr(Index) = null

Index = 13, so you are corrupting RAM - in this case, it happens to be your address counter. Either change you loop termination from 13 to 12, or dimension your array correctly to fix your problem. For example,

dim bytRX(14) as byte // 0..13

NOTE (1)
In your ReadStr routine, you pass address ByRef. It would be more code efficient to pass by value

NOTE(2)
Just call SetBaudrate() once at the beginning of your program (before your main loop) - you don't have to set it each time you access the USART

NOTE(3)
Same with I2C.Initialize - just do it once before your main program loop

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

Post by MarkW » Wed Feb 21, 2007 6:16 pm

Thanks David. I knew it had to be something I was just not seeing. In this case it was the one line of code I should have removed from the example when I converted it to a byte array. I did not need the null byte at the end. Taking that one line out fixed it. The 'byref' was somehing I had tried just before giving up. I'm trying to migrate from PBP to Swordfish on this new project and was doing OK until I started working with the I2C stuff. Anyway, Thanks for the assistance, advice, and the compiler.
Mark

Post Reply