PDA

View Full Version : I2C CONFUSION, Help needed please



FromTheCockpit
- 27th July 2013, 01:00
I am trying to communicate with an I2C device. I have done almost everything I could think of but it is not working. The manual mentions stuff but not exactly matching with the datasheet of the device. The device datasheet mentions something about ACK/NACK which the pbp manual does not mention even once. On top my lack of understanding of I2C has left me with no other option to ask here about what I am doing wrong.

What I have done:
I have tried the following commands:
Value var byte
I2CREAD SDA,SCL,%000110100,0,[Value] ' Tried this
I2CREAD SDA,SCL,$1B0,0,[Value] ' Tried this
I2CREAD SDA,SCL,$1B,0,0,[Value] ' Tried this

Then When I do this:
debug HEX Value ' I am expecting '2E' on my screen. But I am not getting it.
(Location Zero will read 2E in the device)

I attach the section explaining the I2C from the datasheet. The device address is $1B.
Many thanks in advance

(Using 16F688 @ 4 MHz)

rsocor01
- 27th July 2013, 04:29
Did you put the two pull-up 4.7k resistors in the SDA and SCL lines?

Robert

rsocor01
- 27th July 2013, 04:34
Also, you don't need to worry about anything that you highlighted in red. The I2CREAD and I2CWRITE commands take care of that for you.

Robert

FromTheCockpit
- 27th July 2013, 10:01
Did you put the two pull-up 4.7k resistors in the SDA and SCL lines?

Robert

Yes, pull ups are there @ 3.2k.
I tried the statement : I2CREAD SDA,SCL,$1B,0,[VALUE] (is it correct? because I don't had any luck)

FromTheCockpit
- 27th July 2013, 12:24
My Code is this:

Include "modedefs.bas"
DEFINE OSC 4

#CONFIG
ifdef PM_USED
device pic16F688, intrc_osc_noclkout, wdt_on, mclr_on, protect_off
else
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _CP_ON & _CPD_ON & _BOD_ON & _IESO_ON & _FCMEN_ON
endif
#ENDCONFIG

DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 3
DEFINE DEBUG_BAUD 2400
DEFINE DEBUG_MODE 1

DEFINE I2C_SLOW 1
'DEFINE I2C_HOLD 1
'-----------------------------------------------------
PORTA=0
PORTC=0
TRISA = %000100
TRISC = %110000
CMCON0 = 7
ANSEL = 0
OPTION_REG = 128
INTCON=128
'-----------------------------------------------------
Value Var word
'------------------------------------------------------------
SCL Var PortC.5
SDA Var PortC.4
Change Var PortA.2
LED Var PortC.0
'---------------------------------------------------------
Pause 500
DEBUG "Start......",13,10
value=0

Main:
High Led : Pause 1000: Low Led : PAUSE 1000

I2CREAD SDA,SCL,$1B,0,[VALUE],Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
Goto Main

Fail:
toggle portc.2
goto main

PortC.2 keeps toggling along with normal LED.

I have also attached the device datasheet. I really appreciate the help in this.

Demon
- 27th July 2013, 13:44
From PBP manual about I2CREAD:

"Constants should not be used for address..."

Don't know if this can help.

Robert

FromTheCockpit
- 27th July 2013, 16:05
From PBP manual about I2CREAD:

"Constants should not be used for address..."

Don't know if this can help.

Robert

I added two bytes - Addr & Loc
Addr=$1B
Loc=0

Sent - I2CREAD SDA,SCL,Addr,Loc,[Value],Fail

No Luck :(

'-----------
What is also confusing me is the control byte in the manual, the device datasheet does not mention any control byte.
I have an address $1B which I am sending as control and location in the device is being sent as Address according to the manual.

aratti
- 27th July 2013, 16:15
The device you are using is a fast mode device (400 khz) so you have to remove the "DEFINE I2C_SLOW 1" and very likely you have to increase your clock speed (4 MHz could be too slow). Also change the variable into byte (you are using word).

Good luck

Al.

Demon
- 27th July 2013, 16:17
I thought I saw 9 bits used from control in the datasheet you linked.

Maybe you're supposed to use a word and ignore the other 7 bits? Or that could be handled by PBP for I2C?

Do you get only a byte back, word, multiple bytes?

Your circuit does make address 0 right?

(just throwing ideas at you)

Robert

FromTheCockpit
- 27th July 2013, 16:34
Steps Taken:

1) Configuration changed: _INTRC_OSC_NOCLKOUT
2) Made 16f688 run at 8MHz : OSCCON=%01110001
3) Commented DEFINE I2CSLOW 1
4) Value changed to BYte (then to word again)

I get a byte back from the device (from what I have understood). Yes there is an address 0 in the device. I should get back chip ID i.e-'2E' as per the datasheet.

Still no Luck.

LinkMTech
- 27th July 2013, 16:45
I couldn't find detailed info on the Write/Read bit of the device address. But I will guess it is bit 7.
You need to Write to the device first using the address with the "Write" bit set.
$1B or %00011011 becomes $9B or $10011011

Without confirming the proper syntax of the commands, here's something off the top of my noodle:

This will cover steps 1~4 of Section 4.3.2 of the datasheet


I2CWRITE SDA,SCL,[Addr,Loc,] ' Addr plus Write bit = $9B



This will cover steps 5~7 of Section 4.3.2 of the datasheet


I2CREAD SDA,SCL,[Addr,Loc] ' Addr plus Read bit = $1B


Putting it together should get you moving in the right direction.


I2CWRITE SDA,SCL,[Addr,Loc,] ' Addr plus Write bit = $9B
I2CREAD SDA,SCL,[Addr,Loc] ' Addr plus Read bit = $1B


Here's a note to myself that might come in handy too:

FromTheCockpit
- 27th July 2013, 16:53
Tried this:


Pause 500
DEBUG "Start......",13,10
Value=0
Addr=$9B
Loc=0

Main:
High Led : Pause 500: Low Led : PAUSE 500
I2CWRITE SDA,SCL,ADDR,LOC
Addr=$1B : PAUSE 50
I2CREAD SDA,SCL,ADDR,LOC,[VALUE],Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail:
toggle portc.2
goto main

Didn't worked. (Value/Addr/Loc = Byte size)

'=======
Can I not the Micro at 4MHz? The Datasheet says MAX speed is 400KHz, so I assume lower speeds are supported. Am I right?

LinkMTech
- 27th July 2013, 17:00
Remove the PAUSE 50 after I2CWRITE because the device starts sending immediately if its happy.

Then try bit 6 then 5 instead for the Write bit if the Write bit position was a wrong guess.
Bit 6 = $5B
Bit 5 = $3B

LinkMTech
- 27th July 2013, 17:05
Yeah, 400kHz is the max speed so at 4MHz it will run closer to 100kHz

FromTheCockpit
- 27th July 2013, 17:11
OSCCON changed to set 4MHz, internal oscillator.
I2CSLOW 1 stays commented
I2CHOLD 1 stays commented


LED Var PortC.0
Value Var Byte
Addr Var Byte
Loc Var Byte
'---------------------------------------------------------
Pause 500
DEBUG "Start......",13,10
Value=0
Addr=$9B 'Tried $3B,$5B
Loc=0

Main:
High Led : Pause 500: Low Led : PAUSE 500
I2CWRITE SDA,SCL,ADDR,LOC
Addr=$1B
I2CREAD SDA,SCL,ADDR,LOC,[VALUE],Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail:
toggle portc.2
goto main

No Luck :(

> It is bit 7 for R/W (Slave address + write bit)

LinkMTech
- 27th July 2013, 17:21
> It is bit 7 for R/W (Slave address + write bit)

How did you find that?

FromTheCockpit
- 27th July 2013, 17:24
Picked up from the datasheet of the device. That is what I understood, am I wrong?
Though I did tried $3B & $5B.

LinkMTech
- 27th July 2013, 17:33
Not sure if you're wrong or not. I'm still trying to decipher that part in the datasheet because they don't make it easy. I've found that some information has to be gleaned from other devices of the same manufacturer to put the whole story together, kinda sucks!

I also noticed the address stays at $1B after the first loop in your test program and if it works you might miss it.

Note: I just found one of my programs on another I2C device that has bit 1=0 as the Write bit.
$1B = $00011011 used for Read
$1A = $00011010 used for Write

FromTheCockpit
- 27th July 2013, 17:47
I read it again to confirm this, the attachment is my source. It also mentions 9 bits long address. Not sure who sends an ack. I see that in read statement the device send ack, so why add it to the address PIC is sending. Very confusing.

LinkMTech
- 27th July 2013, 18:06
Ahhhh... okay
Let's use this info then. Looks like the address is using bits 1~7 and the Read/Write control bit is 0.
If control bit is set (=1) then Read, if bit cleared (=0) then Write

So:
%00110111 = $37 ' Read function
%00110110 = $36 ' Write function

Try that.

By the way, the device sends the ACK, or acknowledges, by holding the Data line LOW on the 9th clock cycle. The PIC will see this and continue to send data.

FromTheCockpit
- 27th July 2013, 18:38
By the way, the device sends the ACK, or acknowledges, by holding the Data line LOW on the 9th clock cycle. The PIC will see this and continue to send data.
How do I implement this, like this below?

Main:
High Led : Pause 500: Low Led : PAUSE 500
Addr=$36
I2CWRITE SDA,SCL,ADDR,LOC
Addr=$37 : pause 10 ' OR If SDA=1 then main
I2CREAD SDA,SCL,loc,[VALUE],Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail:
toggle portc.2
goto main

LinkMTech
- 27th July 2013, 19:10
Just notice the address missing on the Read function.
Moved the Fail label after Write to test this part first. This will let you know if the Write address was recognized so the Pause 10 is not needed.




Main:
High Led : Pause 500: Low Led : PAUSE 500
Addr=$36
I2CWRITE SDA,SCL,ADDR,LOC, Fail ' Test here first
Addr=$37 ': pause 10 ' OR If SDA=1 then main
I2CREAD SDA,SCL,ADDR,loc,[VALUE] ',Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail:
toggle portc.2
goto main

FromTheCockpit
- 27th July 2013, 19:28
Checked it. It fails on the first write statement.

FromTheCockpit
- 27th July 2013, 19:52
Fails on the second statement if I swap the values of Addr. i.e. First $37, second Addr $36. First one goes fine.

LinkMTech
- 27th July 2013, 19:53
Checked it. It fails on the first write statement.


Okay let's fix that first.
Put brackets around the Loc as shown in the PBP manual to see if that helps.


Main:
High Led : Pause 500: Low Led : PAUSE 500
Addr=$36
I2CWRITE SDA,SCL,ADDR,[LOC],Fail ' Test here first
Addr=$37 ': pause 10 ' OR If SDA=1 then main
I2CREAD SDA,SCL,ADDR,[LOC,VALUE] ',Fail
PAUSE 25
DEBUG HEX Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail:
toggle portc.2
goto main

FromTheCockpit
- 27th July 2013, 20:18
I did exactly the same as above and the sequence completed fine. BUT the values are not consistent with the datasheet, I should get '$2E' from location 0, but WHATEVER location I try to read, I am getting '$FF'

FromTheCockpit
- 27th July 2013, 20:36
Have a look at my real term serial monitor. I am actually getting a lot of unexpected data which I don't understand how is getting stored in just one byte. Though among all this, I can see '2E' (but it is swapped around so 'E2'). Note sure if I am trying to convince myself or the data is rubbish.

FromTheCockpit
- 27th July 2013, 20:40
Better in nibble setting. I can see '2E' repeated a few times.

LinkMTech
- 27th July 2013, 20:46
My bad, change the Read statement:


I2CREAD SDA,SCL,ADDR,[VALUE] ',Fail

FromTheCockpit
- 27th July 2013, 21:32
Still getting the same with the following code:


Value Var BYTE
Addr Var byte
Loc Var Byte
'---------------------------------------------------------
Pause 500
DEBUG "Start......",13,10
Value=0
Loc=0

Main:
High Led : Pause 500: Low Led : PAUSE 500
Addr=$36
I2CWRITE SDA,SCL,ADDR,[LOC],Fail1
Addr=$37 : pause 10 ' Sometimes it is failing, leaving pause 10 makes it better.
I2CREAD SDA,SCL,ADDR,[VALUE] ,Fail2
PAUSE 25
DEBUG Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail1:
while 1: toggle portc.2 : pause 50 : wend
goto main

Fail2:
WHILE 1
High Portc.2 : Pause 250 : Low PortC.2 : Pause 250
WEND

LinkMTech
- 27th July 2013, 21:46
What if you assign the Read/Write addresses before hand?


Value Var BYTE
Addr Var byte
Loc Var Byte

'---------------------------------------------------------
Pause 500
DEBUG "Start......",13,10
Value=0
Loc=0
WR_Add CON $36
RD_Add CON $37

Main:
High Led : Pause 500: Low Led : PAUSE 500
'Addr=$36
I2CWRITE SDA,SCL,WR_Add,[LOC],Fail1
'Addr=$37 : pause 10 ' Sometimes it is failing, leaving pause 10 makes it better.
I2CREAD SDA,SCL,RD_Add,[VALUE] ,Fail2
PAUSE 25
DEBUG Value,13,10
PAUSE 250
DEBUG "Done....",13,10
WHILE 1 : WEND
Goto Main

Fail1:
while 1: toggle portc.2 : pause 50 : wend
goto main

Fail2:
WHILE 1
High Portc.2 : Pause 250 : Low PortC.2 : Pause 250
WEND


Question: Where is the "1" monitored at in these statements? Never seen it done this way before.


WHILE 1: WEND

FromTheCockpit
- 27th July 2013, 22:18
The manual says do not use constants for address.
Though I tried the above but the result is the same.

While 1 : Wend - I just put this just like that to halt the code.

LinkMTech
- 27th July 2013, 22:48
Oh yeah, no Constants.
Then give it to him straight!

Have you tried clearing the LOC and Value variables at the beginning of each loop just in case? Start with a clean slate every time.


Main:
Loc=0
Value=0
High Led : Pause 500: Low Led : PAUSE 500
I2CWRITE SDA,SCL,$36,[LOC],Fail1
I2CREAD SDA,SCL,$37,[VALUE] ,Fail2
PAUSE 25
DEBUG Value,13,10
PAUSE 250
DEBUG "Done....",13,10

WHILE 1 : WEND
Goto Main

Fail1:
while 1: toggle portc.2 : pause 50 : wend
goto main

Fail2:
WHILE 1
High Portc.2 : Pause 250 : Low PortC.2 : Pause 250
WEND


You're so close, I can smell it!
Or was that someone in the room?

FromTheCockpit
- 27th July 2013, 23:23
Did the above, no luck.
Doesn't like it straight, giving it $37/$36 direct sends it to Fail1 routine. So write statement fails.

Funny thing is that when it goes to Fail1, though there should be no output of data, IT does output some of the data. This looks like half the data compared to when cycle runs normally.

The code only run once and then I reset the PIC to run it again, so though it won't make any effect resetting the values in the main loop, I still tried with no luck. I am losing hairs on my head because of this now.

LinkMTech
- 28th July 2013, 00:38
Still Debugging after failing is strange. There is something else being introduced corrupting your instructions.

Use the Addr variables and see what happens when it free runs:


x VAR BYTE
RD_Addr = $37
WR_Addr = $36

Main:
High Led : Pause 500: Low Led : PAUSE 500
I2CWRITE SDA,SCL,WR_Addr,[LOC],Fail1
I2CREAD SDA,SCL,RD_Addr,[VALUE] ,Fail2
PAUSE 25
DEBUG Value,13,10
PAUSE 250
DEBUG "Done....",13,10

WHILE 1 : WEND
Goto Main

Fail1:
FOR x = 0 TO 10
toggle portc.2 : pause 50
NEXT x
goto main

Fail2:
FOR x = 0 TO 10
High Portc.2 : Pause 250 : Low PortC.2 : Pause 250
NEXT x
GOTO Main


Going to church now, BBL

Demon
- 28th July 2013, 00:40
Is that Write only an initialisation?

Shouldn't it be outside the Main loop?

Robert

Demon
- 28th July 2013, 00:50
This is a Touch IC. So shouldn't you check the device ID once, then check at another address within the loop to detect a touch? (not sure of trigger yet)

I'm dense, won't WHILE 1: WEND loop endlessly?

Robert

Edit: I see it now; 1 to 7 keys max for I2C, triggers lines out.

Also, looking in datasheet if it says 400kHz max. I think you might have to run fast.

4.1.1 max 400kHz, so you should be able to run slower.

Demon
- 28th July 2013, 01:17
...
%00110111 = $37 ' Read function
%00110110 = $36 ' Write function
..

I would have thought:
%00000001 = $37 ' Read function
%00000000 = $36 ' Write function

I don't see in this datasheet where you get the rest.

Robert

FromTheCockpit
- 28th July 2013, 12:00
I just discovered, that the I am actually receiving only 1 byte as expected. Rest are just "Start......"13,10 and "Done",13,10. Yesterday got too exhausted and missed this mistake of mine.

Here is the current code with
Start:
Loc=0

Start_Again:
I2CWRITE SDA,SCL,$36,[LOC],Fail1

Main:
Value=0
High Led : Pause 500: Low Led : PAUSE 500
I2CREAD SDA,SCL,$37,[VALUE] ,Fail2
PAUSE 250
DEBUG Value
Loc=Loc+1
If Loc<4 then Start_Again ' Read first 4 locations
x=0

WHILE !Change ' Stay here if Change Stays High
Pause 500 : x=x+1
If x =10 then
LOC=3 : Goto Main ' Do another read
Endif
WEND
while Change : pause 100 : wend ' Stay here if change is Low
Goto Start

Fail1: ' Try Write again
For x=0 to 50
High Portc.2 : Pause 50 : Low PortC.2 : Pause 50
Next x
Goto Start_again

Fail2: ' Try read again
For x=0 to 5
High Portc.2 : Pause 250 : Low PortC.2 : Pause 250
Next x
Goto Main

Every time Change line goes low (detected something), I try to read first 4 memory locations. The communication fails a lot of times (both write and read (write more than read) )in this attempt but I do get the data on the screen finally. Secondly, the data which comes is wrong. For example, memory locations 0 does not read 2E for a start.

FromTheCockpit
- 28th July 2013, 12:41
Success but with one question.
Finally, I put 20MHz clock. It started working with absolutely no problems.

This leaves me with one MAJOR question - Is there any way, I can run the whole show at 4MHz, any settings I missed or anything I can do. I have got no extra pins on my PIC to put an external oscillator, I want to confirm the answer to this question before I start again and choose another suitable PIC. My task will get much much easier if there is a way to run it at 4 Sweet Megahertz.

Many many many thanks to you guys for trying to helping me out on this. This forum is the best.

Demon
- 28th July 2013, 14:36
16F688 can go up to 8MHz on internal oscillator.

I'd try that before changing PIC.

Robert

LinkMTech
- 28th July 2013, 21:28
I put a test circuit together on my LAB-X4 using the PIC16F688 to talk to a 128kB FRAM.
I could feel your pain when trying to make your test program work so decided to start from almost scratch.
The TRIS statements were missing some bit assignments which are not a good thing, from what I read somewhere here by Henrik Olssen, so I put them in.
The order of CONFIG's and other setups were rearranged as well. Not really sure which fixed it but, :D

The end results were that it works at 4MHz and here's the program to compare with.


'
' This setup uses a PIC16F688 and a FM24V01, 128kB Nonvolatile RAM to test
' the I2CREAD/WRITE functions at 4MHz.
'
' First: The FRAM memory is loaded with values 1~5 starting from
' location 0 using Word size address. The values written are sequentially
' loaded into the next memory location, so only the starting address is
' needed for this test.
' Read address = $A0
' Write address = $A1
'
' Second: The FRAM memory locations 0 thru 4 are READ in a loop then stops
' and waits the Test button on the LAB-4X to be pushed and repeats.
'
' The data was monitored with the Saleae Logic scope.
' Max clock speed measured at 4Mhz was 29kHz
'
' The DEBUG function was not used during this test
'************************************************* ***************

#CONFIG
ifdef PM_USED
device pic16F688, intrc_osc_noclkout, wdt_on, mclr_on, protect_off
else
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF
endif
#ENDCONFIG

'-----------------------------------------------------
PORTA=0
PORTC=0
TRISA = %00001000 ' All 8 bits assigned one way or the other
TRISC = %00000000 ' All 8 bits assigned one way or the other
CMCON0 = 7
ANSEL = 0
OPTION_REG = 128 ' PORTA pullups disabled
INTCON=128
OSCCON = %01100001 ' Oscillator set to 4MHz

DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 3
DEFINE DEBUG_BAUD 2400
DEFINE DEBUG_MODE 1
DEFINE OSC 4
Include "modedefs.bas"

'-----------------------------------------------------------
Value VAR BYTE
WR_Addr VAR BYTE
RD_Addr VAR BYTE
LOC VAR WORD ' FRAM address must be sent as Word size
x VAR BYTE
'------------------------------------------------------------
SCL VAR PORTA.4 ' RA4, pin #3
SDA VAR PORTA.5 ' RA5, pin #2
Change VAR PORTA.3 ' Push button on LAB-X4
LED VAR PORTA.0 ' Test LED. LOW = ON
'------------------------------------------------------------
LOC = 0 ' Start at 0
LED = 1 ' Turn LED OFF
PAUSE 1000 ' Give me a chance to start the monitor

GOSUB Load_Mem ' Load FRAM memory locations 0~4 with values 1~5

Main:
FOR LOC = 0 TO 4
LED = 0 ' Turn ON LED, scope monitored
I2CWRITE SDA,SCL,$A0,[LOC],Fail1
PAUSEUS 25 ' Paused to see on display
I2CREAD SDA,SCL,$A1,[VALUE],Fail2
PAUSEUS 500 ' Paused to seperate packets, viewing purpose only
LED =1 ' Turn OFF LED
NEXT LOC

WHILE CHange: WEND ' Wait until button pushed
PAUSE 500 ' Cheap debounce
GOTO Main

'----------------------- Fail routines -------------------------------

Fail1: ' Try Write again
FOR x=0 to 50
LOW LED : PAUSE 50 : HIGH LED : PAUSE 50
Next x
GOTO Main

Fail2: ' Try read again
For x=0 to 5
LOW LED : PAUSE 250 : HIGH LED : PAUSE 250
Next x
GOTO Main

'---------------------- Load FRAM --------------------------------------

Load_Mem:
LED = 0 ' Turn ON LED, scope monitored
I2CWRITE SDA,SCL,$A0,[LOC,1,2,3,4,5],Fail1
LED = 1 ' Turn OFF LED
RETURN

END



This first screenshot is from:


Load_Mem:
LED = 0 ' Turn ON LED, scope monitored
I2CWRITE SDA,SCL,$A0,[LOC,1,2,3,4,5],Fail1
LED = 1 ' Turn OFF LED
RETURN


The 2nd and 3rd from the first and last loop Reads showing the values 1 and 5 after the $A1 READ address.

LinkMTech
- 29th July 2013, 00:54
Okay decided to try the Debug and got fancy while I was at it. This can be addicting! :eek:

Here's the updated code...


'
' This setup uses a PIC16F688 and a FM24V01, 128kB Nonvolatile RAM to test
' the I2CREAD/WRITE functions at 4MHz.
'
' First: The FRAM memory is loaded with values 1~5 starting from
' location 0 using Word size address. The values written are sequentially
' loaded into the next memory location, so only the starting address is
' needed for this test.
' Read address = $A0
' Write address = $A1
'
' Second: The FRAM memory locations 0 thru 4 are READ in a loop then stops
' and waits the Test button on the LAB-4X to be pushed and repeats.
'
' The data was monitored with the Saleae Logic scope.
' Max clock speed measured at 4Mhz was 29kHz
'
' The DEBUG function was used this time.
'************************************************* ***************

#CONFIG
ifdef PM_USED
device pic16F688, intrc_osc_noclkout, wdt_on, mclr_on, protect_off
else
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF
endif
#ENDCONFIG

'-----------------------------------------------------
PORTA=0
PORTC=0
TRISA = %00001000 ' All 8 bits assigned one way or the other
TRISC = %00000000 ' All 8 bits assigned one way or the other
CMCON0 = 7
ANSEL = 0
OPTION_REG = 128 ' PORTA pullups disabled
INTCON=128
OSCCON = %01100001 ' Oscillator set to 4MHz

DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 3
DEFINE DEBUG_BAUD 19200
DEFINE DEBUG_MODE 1
DEFINE OSC 4
Include "modedefs.bas"

'-----------------------------------------------------------
Manf VAR BYTE[3]
Value VAR BYTE
LOC VAR WORD ' FRAM address must be sent as Word size
x VAR BYTE
'------------------------------------------------------------
SCL VAR PORTA.4 ' RA4, pin #3
SDA VAR PORTA.5 ' RA5, pin #2
Change VAR PORTA.3 ' Push button on LAB-X4
LED VAR PORTA.0 ' Test LED. LOW = ON
'------------------------------------------------------------
LOC = 0 ' Start at 0
LED = 1 ' Turn LED OFF
PAUSE 1000 ' Give me a chance to start the monitor

GOSUB Load_Mem ' Load FRAM memory locations 0~4 with values 1~5

Main:
FOR LOC = 0 TO 4
LED = 0 ' Turn ON LED, scope monitored
I2CWRITE SDA,SCL,$A0,[LOC],Fail1
PAUSEUS 25 ' Paused to see on display
I2CREAD SDA,SCL,$A1,[VALUE],Fail2
DEBUG "LOC = ", DEC LOC,", ","Value = ", DEC Value,13,10
LED =1 ' Turn OFF LED
NEXT LOC

DEBUG 13,10 ' Add a space between readings

' Send Reserved Slave ID $F8 and address
I2CWRITE SDA,SCL,$F8,[$A1],Fail1
PAUSEUS 25 ' Paused to see on display

' Send Reserved Slave ID $F9 and address then read in 3 bytes
I2CREAD SDA,SCL,$F9,$A1,[Manf[0], Manf[1], Manf[2]],Fail2

' Debug Manufacture and Product ID. This FRAM = 00x41x00
DEBUG "Manf, & Product ID = ",HEX2 Manf[0],",",HEX2 Manf[1],",",_
HEX2 Manf[2],13,10,13,10

WHILE CHange: WEND ' Wait until button pushed
PAUSE 500 ' Cheap debounce
GOTO Main

'----------------------- Fail routines -------------------------------

Fail1: ' Try Write again
FOR x=0 to 50
LOW LED : PAUSE 50 : HIGH LED : PAUSE 50
Next x
GOTO Main

Fail2: ' Try read again
For x=0 to 5
LOW LED : PAUSE 250 : HIGH LED : PAUSE 250
Next x
GOTO Main

'---------------------- Load FRAM --------------------------------------

Load_Mem:
LED = 0 ' Turn ON LED, scope monitored
I2CWRITE SDA,SCL,$A0,[LOC,1,2,3,4,5],Fail1
LED = 1 ' Turn OFF LED
RETURN

END


Now the Debug at 19.2k..
7052