View previous topic :: View next topic |
Author |
Message |
Guest
|
24LC16B problem |
Posted: Thu Oct 25, 2007 10:12 am |
|
|
I've been facing a very weird problem. I've a PIC16F648A and a 24LC16B. the EEPROM is connected to the PIN_A3 and the PIN_A2 of the 648A. The two lines (SDA and SCL) have a pull-up resistor of 10K.
So the code is as follows:
Code: |
#include <16F648A.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#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 PROTECT
#FUSES PUT //Power Up Timer
#define EEPROM_SCL PIN_A2
#define EEPROM_SDA PIN_A3
#use delay(clock=4000000)
#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL)
void init_ext_eeprom()
{
output_float(EEPROM_SCL);
output_float(EEPROM_SDA);
}
BOOLEAN ext_eeprom_ready()
{
int1 ack;
i2c_start(); // If the write command is acknowledged,
ack = i2c_write(0xa0); // then the device is ready.
i2c_stop();
return !ack;
}
void write_ext_eeprom(long int address, BYTE data)
{
while(!ext_eeprom_ready());
i2c_start();
i2c_write((0xa0|(BYTE)(address>>7))&0xfe);
i2c_write(address);
i2c_write(data);
i2c_stop();
}
BYTE read_ext_eeprom(long int address)
{
BYTE data;
while(!ext_eeprom_ready());
i2c_start();
i2c_write((0xa0|(BYTE)(address>>7))&0xfe);
i2c_write(address);
i2c_start();
i2c_write((0xa0|(BYTE)(address>>7))|1);
data=i2c_read(0);
i2c_stop();
return(data);
}
void main(void)
{
int i = 0;
int j = 0;
int x = 0;
int16 pos_eeprom = 0;
int16 pos_eeprom_aux = 0;
x = 0x41;
pos_eeprom = 2;
pos_eeprom_aux = pos_eeprom;
init_ext_eeprom();
while(TRUE)
{
for (i = 0; i < 500; i++)
{
for (j = 0; j < 3 ; j++)
{
write_ext_eeprom(pos_eeprom++, x+j);
delay_ms(5);
}
for (j = 0; j < 3; j++)
{
if (x+j != read_ext_eeprom(pos_eeprom_aux++))
{
write_eeprom(i, 0x40);
delay_ms(5);
}
}
}
}
}
|
And all the code runs perfectly well, but when the pos_eeprom reaches the value of 0x28 it stops, it does nothing more... why?
But if I test the same code with the internal eeprom I have no error, what is the problem?
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 25, 2007 11:56 am |
|
|
I don't know what your code is supposed to be doing, but there are
a few errors.
Quote: | int i = 0;
for (i = 0; i < 500; i++)
|
There is a problem with this loop.
In CCS an 'int' is an 8-bit unsigned integer. It can only hold a value
from 0 to 255. If you want to hold 500, then you must use an 'int16'.
Quote: | write_eeprom(i, 0x40); |
In your code, you mostly access the external eeprom. Then in this
line, you access the internal eeprom. It that your intention ?
Also the internal eeprom in the 16F648A is only 256 bytes. The address
can only be from 0 to 255. Your loop tries to go from 0 to 499.
If you have any more problems, please post your compiler version.
Also, write a more simple test program. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Oct 25, 2007 3:03 pm |
|
|
I would not have a resistor value higher than 4.7K. A higher value will most likely cause the bus to not work.
Ronald |
|
|
ralph79
Joined: 29 Aug 2007 Posts: 87
|
|
Posted: Fri Oct 26, 2007 7:35 am |
|
|
To PCM Programer:
I think I've assigned my first post because but for some reason it was not signed.
First of all thanks for your reply.
The code I posted here is a very small portion of a bigger code.
This part of code:
Code: |
int i = 0;
for (i = 0; i < 500; i++)
|
was a small test code do determine if the it were any errors in write/read external eeprom.
At the beginning it was a int16, then a long int, an finally a int from 0 to 255. I've made an error in my post.
The internal write memory that is in my code, should only occur any there is an error in the write/read external eeprom.
My compiler version is 4.038
To rnielsen:
I've tried to change my pull-ups resistors from 10K, 4.7K but still no luck
Any other advice?
Best thanks |
|
|
amcfall
Joined: 20 Oct 2005 Posts: 44
|
|
Posted: Fri Oct 26, 2007 8:39 am |
|
|
PCM programmer wrote: |
If you have any more problems, please post your compiler version.
Also, write a more simple test program. |
Do as he asked if you want further help.
Avery |
|
|
ralph79
Joined: 29 Aug 2007 Posts: 87
|
|
Posted: Fri Oct 26, 2007 10:00 am |
|
|
Ok this is my simplest code:
Code: |
#include <16F648A.h>
#define EEPROM_SCL PIN_A2
#define EEPROM_SDA PIN_A3
#define OFF 0
#define ON 1
#include <2416.c>
#FUSES NOWDT,INTRC_IO,NOPROTECT,NOBROWNOUT,NOMCLR,NOCPD,PROTECT,PUT
#use delay(clock=4000000)
void Blink_Led_0(void)
{
output_high(PIN_A0);
delay_ms(500);
output_low(PIN_A0);
delay_ms(500);
}
void Blink_Led_1(void)
{
output_high(PIN_A1);
delay_ms(50);
output_low(PIN_A1);
delay_ms(50);
}
void main(void)
{
int16 pointer, pos_eeprom, pos_eeprom_aux;
int8 value, j;
int1 write_accomplish;
value = 0x41; // "A"
pos_eeprom_aux = pos_eeprom = 2;
write_accomplish = OFF;
init_ext_eeprom();
while(TRUE)
{
if (!write_accomplish)
{
for (pointer = 0; pointer < 500; pointer++)
{
for (j = 0; j < 3 ; j++)
{
write_ext_eeprom(pos_eeprom++, (value + j));
}
for (j = 0; j < 3; j++)
{
if ( (value + j) != read_ext_eeprom(pos_eeprom_aux++) )
{
Blink_Led_0();
}
}
Blink_Led_1();
}
write_accomplish = ON;
}
}
}
|
For some reason, which I don't know what is, several times the 16F648A fails the write/read operation and hangs. In other words it stops in time and the any way to make it work again is make an hardware reset.
My question is: does anybody have ever had a similar problem? If so how he/she accomplish to make it to work.
I even tried to put a small delay of 1ms after each read or write operation but I keep getting the same problem
I've changed also the pull-up resistors values, the microcontroller and also the EEPROM. So, my guess is, the problem is on the software, but I don't know where.
Best regards, |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 26, 2007 11:03 am |
|
|
1. Did you build this board or did you buy it ? If you bought it, what's
the manufacturer and model number ? If you built it, do you have
a 100 nF (0.1 uF) ceramic capacitor between the PIC's Vdd pin and
ground (placed very close to the pins, with short leads) ?
2. Do you have a 10K or 47K pull-up resistor on the MCLR pin ?
(10K for most applications, 47K if you're using the CCS ICD-U40).
3. You should add the NOLVP fuse. I looked at the .LST for vs. 4.038
and it sets the NOLVP fuse by default. That's unusual for CCS.
But you should specify it anyway.
4. What's the Vdd voltage on your board ? Is it +5v or +3.3v ?
Does it come from a voltage regulator ?
5. If you built the board, is it an actual board, or is it a 3M-style
protoboard where all the connections are made with jumper wires ? |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Oct 26, 2007 3:13 pm |
|
|
Is that the actual code that you have compiled and tried? If it is, you are missing all of the initializing statements at the beginning of main() like:
Code: | setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_comparator(NC_NC);
setup_vref(FALSE);
port_a_pullups(TRUE);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_8MHZ);
|
I don't know if these work for the PIC you are using. I simply grabbed it from the project I currently have open.
Ronald |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 26, 2007 3:47 pm |
|
|
Those lines are put in by the CCS IDE Wizard. In the code you posted,
the Wizard is enabling various modules that are used by your program.
In the typical case, the Wizard puts in many lines of code to disable
the PIC's peripheral modules. Example:
Code: | setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_spi(FALSE);
setup_vref(FALSE);
setup_comparator(NC_NC_NC_NC);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_WDT(WDT_OFF); |
These lines are not needed. They turn off modules that are disabled
by default, upon power-on reset. Or in the case of the comparators,
the compiler already puts in start-up code that turns them off.
Also, it puts in start-up code to make the analog pins become digital i/o.
In some cases, when a new PIC is added to the compiler, CCS doesn't
do the start-up code correctly. Then you might need to turn off the
comparators as shown above. Or, that line might not work, and you
need to put in code to write directly to the CMCON register. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Oct 26, 2007 5:18 pm |
|
|
I understand that some of that code may not be needed but I've learned that you can't always trust the compiler to set things up properly 'by default'. That is one that will bite you in the butt. I always put these instructions in to ensure that everything is set up and configured properly. Never 'assume' (and you know what that means) anything, especially when it comes to software meshing with hardware.
Ronald |
|
|
ralph79
Joined: 29 Aug 2007 Posts: 87
|
|
Posted: Sat Oct 27, 2007 3:44 am |
|
|
I've my own board, not a prototype board but a actual PCB board.
The distance between the micro controller and the EEPROM pins is less than one inch. Both the pins SDA, SCL have pull-up resistors.
The board has an voltage regulator (78L05) that feeds the micro controller and the EEPROM. Both (EEPROM and micro) have an ceramic capacitor of 100nF between the Vdd and the Vss to filter the commutation spikes from the chips.
The MCLR pin has an pull-up resistor of 10K.
I will try the NOLVP fuse again, I think that I've already tried but with no luck.
The only thing I didn't really tried is to turn off all the modules I don't use.
In my real code, the one that has been killing my head, because of this strange error I've a little more initialization than I posted here:
Initialization of comport:
Code: |
#use rs232(baud=1200, parity=N, xmit=PIN_B2, rcv=PIN_B1, bits=8, errors)
|
Initialization of timers and others:
Code: |
disable_interrupts(INT_TIMER1);
disable_interrupts(INT_RDA);
disable_interrupts(INT_TIMER0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // div_by_1=128us
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); // div_by_2=131ms
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
// .....................
init_ext_eeprom();
// ........................
|
And the routines that grab the interrupts are:
Code: |
#int_RDA // rs232 receive data available
void RDA_isr(void)
{
/*
......................
.....................
*/
}
#int_TIMER0
void TIMER0_isr(void)
{
/*
......................
.....................
*/
}
#int_TIMER1
void TIMER1_isr(void)
{
/*
......................
.....................
*/
}
|
I even tried to make a:
Code: |
disable_interrupts(GLOBAL);
|
and a:
Code: |
enable_interrupts(GLOBAL);
|
Each time I've made an read write operation to the external EEPROM but with no effect.
What is killing my head is if I change:
Code: |
write_ext_eeprom(pos_eeprom++, (value + j));
|
to
Code: |
write_eeprom(pos_eeprom++, (value + j));
|
and
Code: |
read_ext_eeprom(pos_eeprom_aux++);
|
to
Code: |
read_eeprom(pos_eeprom_aux++);
|
Knowing of course that my internal eeprom have only 256bytes... But I don't have any error. Neither the microcontroller hangs, fails or stopps.
It seems to me that I need vacancies...
Any help would appreciate.
Best regards |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Oct 27, 2007 10:02 am |
|
|
I have a question.
Does your "simplest code" that you posted above actually show
the problem, when you run it ?
Or, do you only see the problem when you run your complete large
program ? |
|
|
ralph79
Joined: 29 Aug 2007 Posts: 87
|
|
Posted: Sat Oct 27, 2007 10:35 am |
|
|
In my "simplest code", only from time to time shows the problem, but it happens.
In my real code, the error happens always from the moment I have 130/140 bytes in my eeprom and I want to write and read a few more.
Until the moment I have only 100/120 bytes in the eeprom I've never noticed any error.
I even tried a small delay (1ms) between each read/write operation but when I get to the position 130/140 it just bangs.
Another test that I've made... Rather begin reading/writing the eeprom from the position zero,what about begin from the position, let's say 100 or 200, and gets what... it bangs.
Do you any clue for this error?
Maybe I'm doing something wrong, but I don't know what is.
If I have an error inside my code, when I work with the internal eeprom I should see the error, but I never did.
My guess is that there is something about the I2C communication. Or some include or define that I should do when I have interrupts or functions /modules in my code.
Might the I2C routine have any code that in some cases could lead to this error?
Thanks for all your patience and feedback.
But I really don't have a clue for this problem-
Best regards |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Sat Oct 27, 2007 12:04 pm |
|
|
Running fine while while the address (number of bytes) is < 128 and hanging when it gets above this may indicate a problem with the most significant address bit. Whether that problem is internal to the PIC or is internal to the external EEPROM has to be determined.
Can you replace the EEPROM to see if the issue goes away? |
|
|
ralph79
Joined: 29 Aug 2007 Posts: 87
|
|
Posted: Sat Oct 27, 2007 12:44 pm |
|
|
I've already replace it and still didn't work.
Unless all the eeproms I have.... have a problem.... which I doubt....
The problem should be in the way the PIC communicates to the eeprom, but I'm not absolute sure.
Does anybody have or had a problem like this?
I just want to see if a determined number of bytes (in a sequential order) is on eeprom and if not the PIC should write that sequence in the eeprom. It should easy.
But I guess not... |
|
|
|