![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Vyperin Guest
|
My I2C communication with EEPROM resets or even hangs my PIC |
Posted: Thu Aug 03, 2006 10:20 pm |
|
|
I am using a 18F1320 PIC, currently connected to one 24LC512 serial EEPROM. All other tasks perform just fine, except the i2c communication to the EEPROM.
For no particular reason the PIC resets itself or hangs when inside a read / write procedure. To make matters worse, i have detected some communication NACK's in the proccess. Beeing in need of connecting more than one EEPROM and software resolving the communication problems, I have extended the driver supplied with the compiler for this type of memory.
Here follows my code:
Code: | #ifndef EEPROM_SDA
#define EEPROM_SDA PIN_B0
#define EEPROM_SCL PIN_A3
#endif
#use delay (clock=20000000)
#use i2c(master,sda=EEPROM_SDA, scl=EEPROM_SCL, fast)
#define EEPROM_ADDRESS long int
#define EEPROM_SIZE 65535
int write_ext_eeprom(byte wraddr, long int address, byte data);
byte read_ext_eeprom(byte wraddr, byte rdaddr, long int address);
void init_ext_eeprom()
{
output_float(EEPROM_SCL);
output_float(EEPROM_SDA);
}
int wr_ee (short int memnr, long int address, byte data)
{
switch (memnr) // A2 A1 A0
{
case 0 : return write_ext_eeprom(0xa0,address,data); // 0 0 0
case 1 : return write_ext_eeprom(0xa2,address,data); // 0 0 1
case 2 : return write_ext_eeprom(0xa4,address,data); // 0 1 0
case 3 : return write_ext_eeprom(0xa6,address,data); // 0 1 1
case 4 : return write_ext_eeprom(0xa8,address,data); // 1 0 0
case 5 : return write_ext_eeprom(0xaa,address,data); // 1 0 1
case 6 : return write_ext_eeprom(0xac,address,data); // 1 1 0
case 7 : return write_ext_eeprom(0xae,address,data); // 1 1 1
default : return 0;
}
}
int write_ext_eeprom(byte wraddr, long int address, byte data)
{
short int status = 1;
int defreeze = 0;
while (status==1 && defreeze++<100) // defreeze++<100>>8);
if (status==1) { i2c_stop(); delay_ms(6); continue; }
status=i2c_write(address);
if (status==1) { i2c_stop(); delay_ms(6); continue; }
status=i2c_write(data);
i2c_stop();
if (status==1) delay_ms(6);
}
if (status==1) return 0;
defreeze = 0;
while(status==1)
{
i2c_start();
status=i2c_write(wraddr);
i2c_stop();
}
return 1;
}
byte rd_ee (short int memnr, long int address)
{
switch (memnr) // A2 A1 A0
{
case 0 : return read_ext_eeprom(0xa0,0xa1,address); // 0 0 0
case 1 : return read_ext_eeprom(0xa2,0xa3,address); // 0 0 1
case 2 : return read_ext_eeprom(0xa4,0xa5,address); // 0 1 0
case 3 : return read_ext_eeprom(0xa6,0xa7,address); // 0 1 1
case 4 : return read_ext_eeprom(0xa8,0xa9,address); // 1 0 0
case 5 : return read_ext_eeprom(0xaa,0xab,address); // 1 0 1
case 6 : return read_ext_eeprom(0xac,0xad,address); // 1 1 0
case 7 : return read_ext_eeprom(0xae,0xaf,address); // 1 1 1
default : return 0x00;
}
}
byte read_ext_eeprom(byte wraddr, byte rdaddr, long int address)
{
byte data = 0x00;
short int status = 1;
int defreeze = 0;
while (status == 1 && defreeze++ < 100) // defreeze++<100>>8);
if (status==1) { i2c_stop(); delay_ms(6); continue; }
status=i2c_write(address);
if (status==1) { i2c_stop(); delay_ms(6); continue; }
i2c_start();
status=i2c_write(rdaddr);
if (status==1) { i2c_stop(); delay_ms(6); continue; }
data=i2c_read(0);
i2c_stop();
}
return data;
} |
So things got a little better after modifying the standard library. But, albitrary, the pic still resets or hangs. Especially (but not only) during long operation, like clearing the memory (this process completes succesfully only 2/10 of times).
I have used both 2k2 and 10k pullups on SDA and SCL. The board is plugged to 5 V and clock is taken from an external crystal oscillator running at 20 MHz. All ports (A and B) are operated on standard_io with no tris specified.
Could anyone give me a suggestion to help work out my issues ? It can be an improvement if I can find out the source of my troubles - hardware or software ?
Thank you. Regards. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Thu Aug 03, 2006 11:01 pm |
|
|
This may or may not be the cause, but it's something that's vexed me before.....
Do you have the watchdog enabled? If it's set for the quickest (18 ms), it may be resetting the PIC while it's waiting for the EEPROM to reply.
I had this same issue and it was the watchdog doing it. I stuck some watchdog resets in the i2c_write() and read() routines, and no problems since. |
|
![](templates/subSilver/images/spacer.gif) |
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Fri Aug 04, 2006 8:31 am |
|
|
If you change this:
#use delay (clock=20000000)
To this:
#use delay (clock=20000000, restart_wdt)
the watch dog timer will be reset in the delay_ms(6) functions. _________________ David |
|
![](templates/subSilver/images/spacer.gif) |
Vyperin Guest
|
Thanks for your prompt posts, but... |
Posted: Fri Aug 04, 2006 2:08 pm |
|
|
... but, I've decided not to use the watchdog because I'm quite inexperienced with this method of self-deblock.
This is my init sequence:
Code: | setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_wdt(WDT_OFF);
setup_oscillator(OSC_NORMAL);
setup_timer_0(RTCC_EXT_L_TO_H);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_EXTERNAL|T3_DIV_BY_1);
|
And theese are my fuses:
Code: | #FUSES NOWDT //No Watch Dog Timer
//#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES NOBROWNOUT //No brownout reset
//#FUSES BORV20 //Brownout reset at 2.0V
//#FUSES NOPUT //No Power Up Timer
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES NOMCLR
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPB //No Boot Block code protection
|
Any other idea would be dully appreciated.
Thank you. |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Aug 04, 2006 10:03 pm |
|
|
Do you have pullups on the lines? |
|
![](templates/subSilver/images/spacer.gif) |
Vyperin Guest
|
The EEPROM has pullups to VCC. |
Posted: Sat Aug 05, 2006 4:18 am |
|
|
I have used both 2K2 and 10K pullups to VCC (5 V) - as specified in documentation. Whatsoever, no significant change occured when I switched over the values.
Because the PIC's clock is 20 MHz and communication is fast, I believe 2K2 is more appropriate than 10K. The distance from the pic's connection to SDA and SCL on the memory is around an inch.
However, my main problem is not solved.
I have tried to include in the #use i2c - force_hw -> and the read / write performs slower and the pic is reseting / blocking much faster.
If you got any other ideas that could solve my problem, please post here.
Thank you. Regards. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Aug 05, 2006 12:46 pm |
|
|
Quote: | I am using a 18F1320 PIC, currently connected to one 24LC512 serial EEPROM.
For no particular reason the PIC resets itself or hangs when inside a read / write procedure. |
This should work. Currently you are trying to fix it by putting band-aids
on the driver. That's the wrong way to solve the problem.
The way I would work on this problem is:
1. Remove all external circuits (chips) except for the EEPROM.
Check all connections. Are you running at +5v or a lower voltage ?
2. Go back to the original, unmodified CCS driver.
3. Get rid of FAST mode in the #use i2c() statement.
4. I would change to a 4 MHz crystal. Possibly you can do this one later.
5. I would write a very simple, very short test program that only reads
from the EEPROM. This could be a loop that sequentially reads all
data within the eeprom. You could send a '.' to the terminal window
on the PC, once per pass, to indicate that the program is still running.
Let that run for 24 hours. See if it locks up. Or, instead of a dot,
you could output a pass-count value (use a 32-bit variable).
Be aware that the terminal program's buffer may have overflowed
when you come in the following morning. You may need to re-start
the terminal program to see if the PIC program is still producing
output.
6. If that works, then do the same thing except use write operations.
7. If that works, then do a full eeprom test program, in which you
write pseudo-random data to the eeprom, and then reload the seed,
and read back the data while comparing it to what was written.
8. If successful, then try going to FAST mode and so on.
In other words, start at the most simple level, get it working there,
and then slowly add complexity.
-------------
Also, post your compiler version. This will be a number such as 3.191,
3.236, 3.249, etc. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|