|
|
View previous topic :: View next topic |
Author |
Message |
davefromnj
Joined: 03 May 2007 Posts: 42
|
I2C intermittent problem |
Posted: Mon Apr 07, 2008 8:21 am |
|
|
Hello All,
I am having an intermittent problem with I2C between the following processors:
PIC18F65J10 and PIC16F677.
The 18F is operating at 4MHz * 4(PLL) = 16MHz.
This is the I2C Master.
The 16F is operating at 4MHz = 4MHz.
This is the I2C Slave.
Out of 18F65J10, 50 boards, 13 have the following problem:
The 18F boards will power up, execute the I2C code, and latch up indefinitely. The other 37 boards work properly, all of the time.
The 18F master, executes the following, initially:
Code: |
if (SSPOV)
{
SSPOV = 0;
}
if (WCOL)
{
WCOL = 0;
}
i2c_start();
temp = i2c_write(slave_address)
///////THE ABOVE COMMAND IS WHERE THE PROCESSOR HANGS.
if (temp)
{
i2c_stop();
i2c_timer = 0;
if (++i2c_timer >= I2C_POLL_DELAY)
{
temp = i2c_write(slave_command)
if (temp)
{ //move on to other i2c commands to read data from slave //16F.
}
}
}
|
Any idea why only certain setups would work and other not work? Is there a way around having the i2c_write() command locking up and waiting for the clock line to be toggled by the slave?
I believe that the slave unit is missing the command, or something is not sync'ing up, so that the master just waits indefinitely for the slave to release the clock line, which never happens.
The slave unit's I2C code:
Code: |
#INT_SSP
BYTE state;
state = i2c_isr_state();
if (state < 0x80) // Master is sending data
{ // First received byte is address
if(state == 1) i2c_command = i2c_read();
}
else if (state == 0x80) // Master is requesting data
{
i2c_cmd_processor(); //This is a function to process the master's commands.
i2c_write_byte(i2c_data); //the i2c_data variable depends on what data the master is asking for.
}
#PRIORITY SSP, TIMER0
|
|
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 8:35 am |
|
|
The problem in I²C almost always come from the reading phases, so please post the code that is used by master to read bytes from the slave.
Matro. |
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 8:43 am |
|
|
Also under your #SSP I see no function declaration but I think it is an error.
Notice that if you can have problems if your "i2c_cmd_processor();" has a long executing time. In this case, it's better to use the NOCLEAR directive and clear yourself the interrupt at the beginning of the function.
One other thing is that you read the received byte only if I2C_isr_state() returns 1. That can introduce problems because the only way to clear the BF (Buffer Full) flag is to read receiving buffer.
You should use something like that :
Code: |
#INT_SSP NOCLEAR
void SSP_isr(void)
{
BYTE state, dummy;
state = i2c_isr_state();
clear_interrupt(int_SSP)
if (state < 0x80) // Master is sending data
{ // First received byte is address
if(state == 1) i2c_command = i2c_read();
else dummy = i2c_read() ; //clear BF flag
}
else if (state == 0x80) // Master is requesting data
{
i2c_cmd_processor(); //This is a function to process the master's commands.
i2c_write_byte(i2c_data); //the i2c_data variable depends on what data the master is asking for.
}
}
|
Matro |
|
|
Guest
|
|
Posted: Mon Apr 07, 2008 8:46 am |
|
|
Code: |
#INT_SSP NOCLEAR
void SSP_isr(void)
{
BYTE state, dummy;
state = i2c_isr_state();
clear_interrupt(int_SSP);
if (state < 0x80) // Master is sending data
{ // First received byte is address
if(state == 1) i2c_command = i2c_read();
else dummy = i2c_read() ; //clear BF flag
}
else if (state == 0x80) // Master is requesting data
{
i2c_cmd_processor(); //This is a function to process the master's commands.
i2c_write_byte(i2c_data); //the i2c_data variable depends on what data the master is asking for.
}
}
|
A ';' was missing in my previous post.
Always interested in seeing the master code that reads the data from slave. ;-)
Matro. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Mon Apr 07, 2008 8:53 am |
|
|
If the master is sending commands faster than the slave can process them the line will lock up. Since there are variances in all parts, the crystals in this case, the parts on one board can be running at slower, or faster, speeds than the other boards. You might try monitoring the bus with a scope to see if this is happening. Adding slight delays between each command to see if that's where the culprit is could help.
The timing, of the I2C bus, just might be barely working on your good boards and barely failing on your bad boards. I've had projects that I had to slow down the rate of commands sent by the master to allow the slave to keep up.
Ronald |
|
|
davefromnj
Joined: 03 May 2007 Posts: 42
|
Thanks for your suggestions |
Posted: Mon Apr 07, 2008 8:59 am |
|
|
Hello all,
Thank you for your suggestions, I am trying them now.
One thing to note:
The same slave board was used to test the 50 master boards, so the variance in this case was on the master 18F boards.
I tried removing all functions in the program except for the I2C routine in a known bad master board.
Result: still latched up on the same i2c command.
I tried removing all functions in the program except for the I2c routine in a known bad board, and set both the master and slave clock to 4MHz.
Result: still latched up on the same i2c command.
The next thing I'm going to try is that NOCLEAR, and dummy = i2c_read() idea. I'll post the results. |
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 9:06 am |
|
|
Does the lock appears during a write or a read command?
Once again please post the piece of code that is used by the master to read from the slave.
If the real problem is here, no improvement will have an effect.
Matro. |
|
|
davefromnj
Joined: 03 May 2007 Posts: 42
|
the processor hangs on the first WRITE command. |
Posted: Mon Apr 07, 2008 9:33 am |
|
|
Matro wrote: | Does the lock appears during a write or a read command?
Once again please post the piece of code that is used by the master to read from the slave.
If the real problem is here, no improvement will have an effect.
Matro. |
This is the last line of code that is executed before the processor hangs, from the first post I made:
Code: |
temp = i2c_write(slave_address)
///////THE ABOVE COMMAND IS WHERE THE PROCESSOR HANGS.
|
Because this is as far as the processor gets, I don't think the other I2C commands are relevant, since they are never executed because the Master main program runs, executes that command, waits for the Slave to toggle the Clock pin, it never does, and waits forever, effectively locking up.
I tried the NOCLEAR, the dummy=i2c_read();, and the clear_interrupt(int_ssp) on the slave board, but still no luck, the board hangs at exactly the same place.
I am beginning to think this is a timing / tolerance related issue since 37 different boards did work.
It would be nice if the i2c_write() command was not blocking, so that a timer1_isr could expire and act as a timeout if the slave does not respond with an ACK.
Do I really have to create my own i2c_write() to have it non-blocking?[/code] |
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 9:49 am |
|
|
I²C can be in trouble if the tris of the port where the I²C is is changed during an I²C operation.
Did you foresee that in your code (for example by using fixed_io or fast_io) ?
Did you look at the I²C bus with a scope to catch what happens?
Do you place the NOLVP fuse in your code?
Could you post your #FUSES and #use i2c lines?
Matro. |
|
|
davefromnj
Joined: 03 May 2007 Posts: 42
|
|
Posted: Mon Apr 07, 2008 10:00 am |
|
|
Matro wrote: | I²C can be in trouble if the tris of the port where the I²C is is changed during an I²C operation.
1]Did you foresee that in your code (for example by using fixed_io or fast_io) ?
2]Did you look at the I²C bus with a scope to catch what happens?
3]Do you place the NOLVP fuse in your code?
Could you post your #FUSES and #use i2c lines?
Matro. |
1] I do not have fixed_io or fast_io, I use the default when I set the tris registers for each output, and only do it ONCE in the main() section of the program.
2] I am in the process of checking the I2C with a scope now to see if data is being sent, however on 37 of the other boards, this does work 100% of the time so this is a very tricky problem...
3] Neither of my processors have the NOLVP fuse as an option. I checked the processor header files, and when I compile with the NOLVP fuse statement, the compiler gives me an error.
Fuses on the master board (18F65J10)
Code: | #DEVICE adc=10 // 10-bit A/D resolution
//#FUSES WDT128 //Watch Dog Timer, 1:128 Postscale
//#FUSES H4_SW //High speed osc with SW enabled 4x PL
//#FUSES INTRC //Internal RC Osc
#FUSES HS //High Speed, Ceramic Resonator, 4MHz
#FUSES NOWDT //No Watch Dog Timer
//#FUSES NODEBUG //No Debug mode for ICD
//#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
//#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOPROTECT //Code not protected from reading
//#FUSES FCMEN //Fail-safe clock monitor enabled
//#FUSES IESO //Internal External Switch Over mode enabled
//#FUSES PRIMARY //Primary clock is system clock when scs=00
|
fuses on the slave board(PIC16F677)
Code: |
#DEVICE adc=10 // 10-bit A/D resolution
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal Osc. <=4Mhz
//#FUSES HS //INTRC
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 07, 2008 11:20 am |
|
|
Quote: |
I do not have fixed_io or fast_io, I use the default when I set the tris registers for each output, and only do it ONCE in the main() section of the program. |
If you don't specify fast i/o mode, then the compiler will be in Standard
I/O mode. In that mode, the compiler sets the TRIS for you, if you use
the built-in i2c functions. You can confirm this for yourself by looking at
the .LST file. Set the List file format to "Symbolic" mode first.
Regarding trouble-shooting the problem:
1. Verify all the normal stuff. i.e., all Vdd pins have a 100 nF (0.1 uF)
ceramic capacitor to ground. The caps should be very close to the PIC.
You should have the correct value for the pull-up resistors (1.6K to 4.7K
should be good). There should be a good ground connection between
the two boards. I'm assuming that you don't have a long cable between
the boards. If you do, what is the cable length ?
2. Don't try to run the Master in FAST mode. Run it in SLOW mode
(100 KHz or less).
3. As a test, increase the oscillator frequency of the slave to 20 MHz.
Substitute a 20 MHz crystal for the 4 MHz one. Change the fuse to HS.
4. Do we know for sure that the problem is in the Master boards ?
Test this by taking a master board that is known to fail, and connect it
to a slave that is running a more conventional PIC, such as a 16F877 or
18F452. Run the PIC at 20 MHz. See if you still get a failure. |
|
|
davefromnj
Joined: 03 May 2007 Posts: 42
|
Thanks for the suggestions... |
Posted: Mon Apr 07, 2008 11:48 am |
|
|
PCM programmer wrote: | Quote: |
I do not have fixed_io or fast_io, I use the default when I set the tris registers for each output, and only do it ONCE in the main() section of the program. |
If you don't specify fast i/o mode, then the compiler will be in Standard
I/O mode. In that mode, the compiler sets the TRIS for you, if you use
the built-in i2c functions. You can confirm this for yourself by looking at
the .LST file. Set the List file format to "Symbolic" mode first.
Regarding trouble-shooting the problem:
1. Verify all the normal stuff. i.e., all Vdd pins have a 100 nF (0.1 uF)
ceramic capacitor to ground. The caps should be very close to the PIC.
You should have the correct value for the pull-up resistors (1.6K to 4.7K
should be good). There should be a good ground connection between
the two boards. I'm assuming that you don't have a long cable between
the boards. If you do, what is the cable length ?
2. Don't try to run the Master in FAST mode. Run it in SLOW mode
(100 KHz or less).
3. As a test, increase the oscillator frequency of the slave to 20 MHz.
Substitute a 20 MHz crystal for the 4 MHz one. Change the fuse to HS.
4. Do we know for sure that the problem is in the Master boards ?
Test this by taking a master board that is known to fail, and connect it
to a slave that is running a more conventional PIC, such as a 16F877 or
18F452. Run the PIC at 20 MHz. See if you still get a failure. |
1], The distance between the boards is less than 4 inches. Both boards are powered from the same source and are using the same ground.
The pullup resistors are 4.7k ohm on the SDA and SCL pin. They are however pulled up to 5V. The PIC16F677 slave is operating on a 5V bus. The PIC18F65J10 master is operating on a 3.3V bus. I used 0.01uF caps on each of the VDD pins, and parts are very close to the processor, and the pins go directly to the microcontroller's VDD and GND pins.
2] The master and slave are both run in slow mode:
Slave:
Code: | #use i2c(Slave,Slow,sda=PIN_B4,scl=PIN_B6,Address=0xA0,force_hw) |
Master:
Code: | #use i2c(Slave,Slow,sda=PIN_B4,scl=PIN_B6,Address=0xA0,force_hw) |
3] I will be ordering faster ceramic resonators today, however, as a test, I removed all the code except for the i2c routines, and then ran both the master and slave at 4MHz, and still the same problem with a troubled board.
4] The problem seems to be on the Master boards, I tested every single Master board with the same slave board, and got a 13/50 failure rate. |
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 11:53 am |
|
|
How is it possible that the voltage levels be different for master and slave?
Do you have a level shifter?
Why is your master configured as slave?...
Just configure it as master and don't give it an address (a master hasn't any).
If your master is configured as slave and moreover you have a PIC running at a voltage that is not the same as the bus... of course you have troubles...
Your luck is that some boards are working...
Matro. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 07, 2008 11:56 am |
|
|
Quote: |
The problem seems to be on the Master boards, I tested every single
Master board with the same slave board, and got a 13/50 failure rate | Right, but try a PIC that is known to be reliable as the Slave PIC.
(16F877 or 18F452). A lot of the newer PICs have bugs with the SSP,
and Microchip doesn't know about all of them yet. Order the reliable
PICs at the same time as you order the other parts.
Quote: | I will be ordering faster ceramic resonators today |
You could temporarily use the internal oscillator on the 16F677 and
run it at 8 MHz. Use the INTRC_IO fuse for this. Set the #use delay()
statement to 8 MHz. |
|
|
mskala
Joined: 06 Mar 2007 Posts: 100 Location: Massachusetts, USA
|
|
Posted: Mon Apr 07, 2008 1:27 pm |
|
|
Matro wrote: | ... you have a PIC running at a voltage that is not the same as the bus... of course you have troubles...
Matro. |
For I2C, if you have a device running on 3.3V, but the pins are 5V-tolerant, then it is perfectly fine to use the pullups to 5V and run the other devices at 5V, without any type of level-shifter. Everything on the bus is open-collector.
By my look at the datasheet, those pins are 5V tolerant. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|