Page 1 of 1

EB006 with PIC16F88 - EEPROM issue.

Posted: Tue Apr 10, 2012 8:22 pm
by Phaenix
I'm trying to write a value to the EEPROM, received from button inputs (see my other thread about the Keypad).

For now I'm doing it with a switch board...

Code: Select all

#include <system.h>

void setup_hardware(void)
{
	trisb = 0xff;
	trisa = 0xe0;
	
	porta = 0x00;
}

void write_eeprom(unsigned char address, unsigned char data)
{
	while (eecon1 & WR);
	
	eeadr = address;
	eedata = data;
	
	clear_bit(eecon1, EEPGD);
	
	set_bit(eecon1, WREN);
	
	clear_bit(intcon, GIE);
	
	eecon2 = 0x55;
	eecon2 = 0xAA;
	
	set_bit(eecon1, WR);
	
	set_bit(intcon, GIE);
	
	clear_bit(eecon1, WREN);
}

unsigned char read_eeprom(unsigned char address)
{
	unsigned char data = 0;
	
	eeadr = address;
	
	clear_bit(eecon1, EEPGD);
	
	set_bit(eecon1, RD);
	
	data = eedata;
	
	return data;
}

int read_eeprom_int(unsigned char address)
{
	unsigned char high, low;
	int data;
	
	low = read_eeprom(address);
	high = read_eeprom(address+1);
	
	data = high * 256;
	data = data + low;
	
	return data;
}

void write_eeprom_int(unsigned char address, int data)
{
	unsigned char high, low;
	
	low = data % 256;
	high = data / 256;
	
	write_eeprom(address, low);
	write_eeprom(address+1, high);
}

unsigned char get_digit(void)
{
	unsigned char count = 0;
	unsigned char oldv, newv;
	oldv = portb ^ 0x00;
	while(count < 20)
	{
		newv = portb ^ 0x00;
		if (oldv == newv)
		{
			count++;
		}
		else
		{
			count = 0;
			oldv = newv;
		}
	}
	return oldv;
}

int get_value(void)
{
	int total = 0, x;
	unsigned char i, k;
	
	for(i=0;i<4;i++)
	{
		while(get_digit() == 0);
		k = get_digit();
		total = total * 10;
		total = total + k;
		for(x=0;x<16000;x++);
	}
	return total;
}

void main(void)
{
	setup_hardware();
	
	int key, attempt, v;
	
	write_eeprom_int(1, 1536);
	
	key = read_eeprom_int(1);

	if (key == 1536)
	{
		porta = 0x01;
	}
}
The following code is ought to write 1536 (split up into two 8-bit numbers) to a place in the EEPROM (1 and 2, here) and then get it back. I put a simple check in it to see if it was succesful. It wasn't. The first LED on porta does not lit up.

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Wed Apr 11, 2012 9:36 am
by Benj
Have you tried with bytes to see if the problem is with the EEPROM functions or the Int to Byte functions.

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Wed Apr 11, 2012 1:52 pm
by Phaenix
The problem is with the splitting up of the large number. The write_eeprom and read_eeprom functions work.

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Wed Apr 11, 2012 2:40 pm
by Benj
Hello,

Yes I see the problem now.

In your write function this code.

Code: Select all

   low = data % 256;
   high = data / 256;
Should look like this.

Code: Select all

   low = data & 0xFF;
   high = data >> 8;
And your read function should also maybe look something like this for better efficiency.

Code: Select all

   data = high << 8;
   data = data + low;
Because the address is always in a power of 2 I would multiply the address by 2 in both the read and write 16-bit int functions before you pass to the byte functions so that you are simply addressing using 0,1, 2 etc instead of 0, 2, 4.

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Wed Apr 11, 2012 3:39 pm
by Phaenix
I changed it, but I think I found a different problem. When I write several things to the EEPROM using the write_eeprom function, it only writes the first... for example if I did:

Code: Select all

write_eeprom(0, 205);
write_eeprom(1, 6);
write_eeprom(2, 16);
write_eeprom(3, 25);
etc...
only write_eeprom(0, 205); gets done

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Fri Apr 13, 2012 9:01 am
by Phaenix
Does anyone know why it does that?

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Fri Apr 13, 2012 9:41 am
by Benj
Hello,

Try changing your write function to look like this.

Code: Select all

void write_eeprom(unsigned char address, unsigned char data)
{
   char intsave = test_bit(intcon, GIE);

   while (test_bit(eecon1, WR));
   
   eeadr = address;
   eedata = data;
   
   clear_bit(eecon1, EEPGD);
   
   set_bit(eecon1, WREN);
   
   clear_bit(intcon, GIE);
   
   eecon2 = 0x55;
   eecon2 = 0xAA;
   
   set_bit(eecon1, WR);
   while (test_bit(eecon1, WR));

   if (intsave)
       set_bit(intcon, GIE);
   
   clear_bit(eecon1, WREN);
}

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Fri Apr 13, 2012 10:04 am
by Phaenix
It works now, thank you!

Do you mind explaining why those 'checks' for lack of a better term are necessary? Or rather, why mine wouldn't work for more than one write every time I ran the program?

Re: EB006 with PIC16F88 - EEPROM issue.

Posted: Fri Apr 13, 2012 10:49 am
by Benj
Hello,

I think one of the main problems you had was this line.

Code: Select all

while (eecon1 & WR);
This syntax is not correct and not doing what you expect. This code would have worked.

Code: Select all

while (eecon1 & (1<<WR));
i.e. WR is the bit number and not a mask, shifting 1 by the bit number produces a mask we can use. I like the test_bit function instead as it looks slightly cleaner and does pretty much the same thing.

The second check I added at the end of the function waits for the write to complete before clearing the WREN bit. This could also have been causing issues if the write functionality was switched off before the data had gone into the memory.