Is this typical I2C behaviour?

wapo54001

Senior Member
I know little about how I2C is supposed to behave so I don’t know if I have a problem or not. I’d like to ask for opinions as to whether my situation is “normal” or whether some improvement is possible. If this is typical behavior I’ll be satisfied; if it’s not and should be better, I’ll start looking deeper.

I have a 20X2 at 16MHz operating as master and a 28X2 at 32MHz operating as slave. Task-wise, the 20X2 pretty much loafs along, but the 28X2 has a demanding, continuous task and there are no PAUSEs in the main loop.

The I2C on the slave 28X is set up to hardware interrupt when data arrives in the scratchpad – two bites at locations 0 and 1. The 28X2 then reads the data and adjusts main loop operating parameters based on that new data.

Here is the issue: The only way I can get data transferred reliably from the 20X2 to the 28X2 is to send it three times consecutively with PAUSE 20s between each transmission. By doing this, the data transfer appears to be perfect as far as I can tell. Without the three transmissions it gets very unreliable. Also, pauses of less than 20 also seem to make the transfer unreliable. Why does it work so well with repeated transmits and rarely works with a single transmit?

Transfer verification by having the master read back the slave scratchpad doesn’t work at all. I would like to have a verification process whereby the master reads the slave’s scratchpad to verify that the information reached the slave, however I cannot read the slave from the master to verify the information arrived safely. When I try to query, all I get is 255, 255.

So, given the fully-occupied state of the slave, is this reasonable behavior or should I look for a problem somewhere that is preventing the system from working properly? The I2C code I’m using in both the slave and the master are straight from working examples posted in the forum and seems to be working with the above caveats. Some of the examples of I2C code in the forum have short pause commands scattered around but I cannot make sense of the logic of them so don’t know if I2C needs pauses anywhere or not.
 

geoff07

Senior Member
Perhaps the thing to do is create a test setup where the chips aren't doing anything else. Get that working and then introduce other activities one by one until you find the failure. Otherwise you have little chance of finding out what is going on.

The other thing to try is to get a scope on the data link and capture the transmission bit patterns, ideally onto paper. Then you can see what the protocol is doing and compare that with what i2c should do (well defined in Philips papers and simple to follow). Not so easy but a cheap scope and a camera or printer can be very useful, if only to verify that things are doing what they should.
 

rossko57

Senior Member
If one of the X2 is "busy busy", perhaps that's the one that ought to be the I2C master, initiating comms at its convenience.
 

wapo54001

Senior Member
If one of the X2 is "busy busy", perhaps that's the one that ought to be the I2C master, initiating comms at its convenience.
Unfortunately the changes are not on any consistent schedule so must be initiated by the 20X2 which senses when changes occur.
 

darb1972

Senior Member
I'm no I2C expert either. But as Goey said, a copy of your code would be very helpful. Also, we can't (at this point) rule out a hardware issue. Things to consider are bus length, data and clock pull ups etc. Are the two PICAXE running off the same supply and ground? Is the supply mains derived and if so, is it considered stable and relatively noise free?

Code and schematics and photos would be a good thing to post so the folks here can assist further.
 

wapo54001

Senior Member
I'm no I2C expert either. But as Goey said, a copy of your code would be very helpful. Also, we can't (at this point) rule out a hardware issue. Things to consider are bus length, data and clock pull ups etc. Are the two PICAXE running off the same supply and ground? Is the supply mains derived and if so, is it considered stable and relatively noise free?

Code and schematics and photos would be a good thing to post so the folks here can assist further.
My original question was "Is this typical I2C Behavior?" and was intended to be very general -- does it look like I have a problem, or is this about how it goes with I2C? I was hoping get a consensus on that question so I could decide whether to trouble shoot this, or move on and put my energy somewhere else. Really, I wasn't asking for help in solving a problem at this point, only some help in deciding if there actually is a problem or not. That's why I didn't post any code or schematics, I would not do that until I had exhausted my own troubleshooting ideas.
 

bpowell

Senior Member
No, this is NOT typical I2C behavior. I2C is a very robust communication protocol that works great. I use it frequently...EEPROM, RTC, MC to MC...all good.
 

darb1972

Senior Member
My original question was "Is this typical I2C Behavior?" and was intended to be very general -- does it look like I have a problem, or is this about how it goes with I2C? I was hoping get a consensus on that question so I could decide whether to trouble shoot this, or move on and put my energy somewhere else. Really, I wasn't asking for help in solving a problem at this point, only some help in deciding if there actually is a problem or not. That's why I didn't post any code or schematics, I would not do that until I had exhausted my own troubleshooting ideas.

Wapo, although only a few people have replied, the fact that they have asked for further details/information probably suggests that they are cautiously suggesting there is an issue.

Again, I am no authority on I2C, but having to send data three times to ensure results/stability certainly doesn't seem right to me (certainly not typical). If you have used what is supposedly working code from the forum then it is not out of the question to suggest a possible hardware issue. There are limits on the bus in terms of length and the pull ups are important and even more so when the bus is at it's absolute limits in terms of working length. I believe the bus pull ups might need to be changed a bit in value for a long bus length. Stray capacitance on the bus might cause wave shape/slew issues. Noise from a psu might cause dramas with data and clock integrity. I only asked for code and schematics/circuit description to assist in troubleshooting.

The mention of pauses throughout the code might be used to comply with some of the I2C timing protocols. Again, I was only asking for code so folks can spot potential issues.
 

Technical

Technical Support
Staff member
The I2C on the slave 28X is set up to hardware interrupt when data arrives in the scratchpad – two bites at locations 0 and 1.
How are you generating the hardware interrupt - by wiring the i2c pins to another pin?
Reading 255 is normally the result of the i2c not responding at all, the 255 comes from the pullup resistor itself.
 

wapo54001

Senior Member
How are you generating the hardware interrupt - by wiring the i2c pins to another pin?
Reading 255 is normally the result of the i2c not responding at all, the 255 comes from the pullup resistor itself.
Oops, maybe not. I barely know enough to scrape by, so keep that in mind . . .

On the slave, I use a 1 meg pulldown on SDA to test if I2C is connected and, if not, potentiometers take control. The I2C pullups are on the separate 20X2 board and they override the 1 meg if connected.

Code:
'determine if control is via potentiometer or via I2C
IF pinC.4 = 1 THEN
	I2C_Ctrl = True 'I2C control active
	'I2C Setup
	HI2CSETUP I2CSLAVE, %10100000
	setintflags %01000000,%01000000
ELSE
	I2C_Ctrl = False 'potentiometer control active
ENDIF
The interrupt routine is:

Code:
interrupt:
  bptr = 28
  pause 10
  for ptr = 0 to hi2clast
    get ptr,@bptrinc 
  next                      
let hi2cflag = 0       'interrupt reset
setintflags %01000000,%01000000
return   'to main
The I2C master I2C code is this:


Code:
'I2C setup
HI2CSETUP i2cmaster, %10100000, i2cslow_16, i2cbyte
When there is data to send, I run this code:

Code:
HI2COUT 0,(Pot1Val,Pot2Val) ' send Pot1Val & Pot2Val in 2 bytes to address 0
PAUSE 20
HI2COUT 0,(Pot1Val,Pot2Val) 
PAUSE 20
HI2COUT 0,(Pot1Val,Pot2Val)
The system works with this code, but I cannot verify arrival so can't resend if required, and it seems to me that I'm sending information unnecessarily because I can't verify arrival.
 

Technical

Technical Support
Staff member
So you
- send 2 i2c bytes from master
- receive 1 byte into slave, then do interrupt
- interrupt then uses a loop based i2clast/flag -which can be affected by the second byte coming in
- you then also use 'get' and 'ptr' in the same command, which can get very confusing (we suggest using @bptrinc = @ptr instead)

As you are background receiving 2 bytes the i2clast / flag and the scratchpad values may change during the loop within 'interrupt', which is activated by the first of 2 bytes, so the second one may come in whilst already processing?

Also a 1M pull down gives you a non-standard i2c interface.

Try simplifying your program down into much simpler block first. e.g. get 2 bytes transferring and verifying with a much simpler test program.
Get these simpler programs working first and then merge them into your more complex main program later.
 

wapo54001

Senior Member
Try simplifying your program down into much simpler block first. e.g. get 2 bytes transferring and verifying with a much simpler test program. Get these simpler programs working first and then merge them into your more complex main program later.
My Gawd! It's a murracle that it's working at all! Much to fix here, thank you for the insights, I'll get to work on this . . .
 

darb1972

Senior Member
Hi Wapo

Glad to hear that Technical got you sorted. That's why I was asking for further information. I wasn't having a go at you, I was just asking for further info so folks here could help. We can only offer suggestions and assistance once we have the full picture.

You will find (as I have in the past) that the folks here will bend over backwards to help you provided you give all the information as needed.

There is very few feelings that rival the exhilaration of solving an ongoing and often complex problem.

Well done Wapo!!!
 

wapo54001

Senior Member
So you
- send 2 i2c bytes from master
- receive 1 byte into slave, then do interrupt
- interrupt then uses a loop based i2clast/flag -which can be affected by the second byte coming in
- you then also use 'get' and 'ptr' in the same command, which can get very confusing (we suggest using @bptrinc = @ptr instead)

As you are background receiving 2 bytes the i2clast / flag and the scratchpad values may change during the loop within 'interrupt', which is activated by the first of 2 bytes, so the second one may come in whilst already processing?

Also a 1M pull down gives you a non-standard i2c interface.

Try simplifying your program down into much simpler block first. e.g. get 2 bytes transferring and verifying with a much simpler test program.
Get these simpler programs working first and then merge them into your more complex main program later.

I'm looking at the issue of the I2C interrupt happening when the first of two bytes arrives at the slave scratchpad but needing to delay processing until the second of the two bytes has also arrived in scratchpad.

What I can see doing is maybe

a) put a PAUSE at the beginning of the interrupt code long enough to allow the second byte to arrive before processing or,

b) put a loop at the beginning of the interrupt code that checks for the second byte location to be non-zero (with the previous interrupt having reset it to zero as it returns to the main program) before processing the two bytes.

Is there a way to make the interrupt trigger only after the second byte has arrived in scratchpad? Or is there some other more elegant way to wait until the second byte has arrived before moving the data from scratchpad into variables to process?
 

hippy

Technical Support
Staff member
Untested but you can use the 'hi2clast' variable to tell where that last incoming byte was placed. If your first byte goes to location zero, the second to location 1 ...

Interrupt:
Do : Loop Until hi2clast > 0
etc
 
Top