|
|
View previous topic :: View next topic |
Author |
Message |
semmoor
Joined: 09 May 2012 Posts: 46 Location: KSA
|
PIC, I2C, EEPROM, PROBLEM |
Posted: Mon Jul 23, 2012 6:01 am |
|
|
Hi guys,
I have a project using 2 PIC master and slave and serial eeprom connected to the master pic. all devices connected using i2c.
When I request data from slave and store it in eeprom it works fine, but when I send another command to slave it does not accept it.
Which means the slave pic only accepts the first command which is to send the data to the master when master asks the slave.
I hope if I can get some help.
master:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#define SLAVE_WRT_ADDR 0x14
#define SLAVE_READ_ADDR 0x15
#include "2416.c"
int8 data_from_slave=0x00;
//This program sends 's' and 'r' to turn on LEDs in Slave PIC
//and receive data from slave to be stored in eeprom and read it from //eeprom to turn on LEDs on Master PIC.
main()
{
//now read data from slave
i2c_start();
i2c_write(SLAVE_READ_ADDR);
data_from_slave = i2c_read(0);
i2c_stop();
//below code turns on LEDs by reading eeporm stored value
printf("Start\n\r\n\r");
init_ext_eeprom();
write_ext_eeprom(000, data_from_slave); //write 0xF0 received form slave at address 0
printf("I Wrote 0xF0 to eeprom address 0\n\r");
printf("This is the stord value %X\n\r", read_ext_eeprom(000));
.
printf("LEDs should be ON corresponding to eeprom stored value\n\r"); output_b(read_ext_eeprom(000));
delay_ms(1000);
//now send 's' and 'r' to turn on and off LEDs on the slave, ! this is the problem master can't send these commands
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('s');
i2c_stop(); delay_ms(1000);
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('r');
i2c_stop(); delay_ms(1000);
printf("\n\rDone\n\r");
while(1);
}
|
slave code:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0x14)
int8 incoming = 0, state;
BYTE address, buffer[0x10];
#INT_SSP
void ssp_isr(void)
{
state = i2c_isr_state();
if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state >= 0x80) // Master is requesting data from slave
{
i2c_write(0xf0);
}
switch(incoming) //test value sent by master
{
case 's':
output_d(0xff);
break;
case 'r':
output_d(0x00);
//write_ext_eeprom(000, 0xFF);
break;
}
}
void main ()
{
setup_adc_ports(NO_ANALOGS);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
//init_ext_eeprom();
while(1)
{
}
}
|
|
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Jul 23, 2012 6:32 am |
|
|
You have read 2416.c, haven't you?
It has its own use i2c, and it defaults to pin E0 for SDA and E1 for SCL. If you want to override those settings you must define EEPROM_SDA before including 2416.c.
Code: |
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#include "2416.c"
|
...and then you don't need, AND SHOULD NOT HAVE, a use i2c in your code.
You should only call init_ext_eeprom() once: before doing ANY i2c stuff, not just the 2416 external eeprom stuff.
What you've ended up with is that its not using the pins you think it is for i2c. Also the two i2c users, the 2416 stuff and your stuff, may well be trying to use different pins. All in all its confused. No wonder it doesn't work.
There may be other problems that others will tell you about. This just was what struck me as "wrong".
RF Developer |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Jul 23, 2012 7:15 am |
|
|
and....
1) be sure to use the correct pullup resistors on the I2C buss lines..
2) download and run PCM pgrms I2C test program !!
hth
jay |
|
|
semmoor
Joined: 09 May 2012 Posts: 46 Location: KSA
|
|
Posted: Mon Jul 23, 2012 11:29 am |
|
|
RF_Developer wrote: | You have read 2416.c, haven't you?
It has its own use i2c, and it defaults to pin E0 for SDA and E1 for SCL. If you want to override those settings you must define EEPROM_SDA before including 2416.c.
Code: |
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#include "2416.c"
|
...and then you don't need, AND SHOULD NOT HAVE, a use i2c in your code.
You should only call init_ext_eeprom() once: before doing ANY i2c stuff, not just the 2416 external eeprom stuff.
What you've ended up with is that its not using the pins you think it is for i2c. Also the two i2c users, the 2416 stuff and your stuff, may well be trying to use different pins. All in all its confused. No wonder it doesn't work.
There may be other problems that others will tell you about. This just was what struck me as "wrong".
RF Developer |
I did exactly that, but didn't work i think the problem is with proteus??
maybe not sure! |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Jul 24, 2012 3:35 am |
|
|
You mentioned the bad P word!
At least 80% of the people on this forum will now stop reading.
Years ago I did play a bit with Proteus and it is quick to connect parts together, but when you run into problems you will find it is difficult to use and is full of bugs. People on this forum want to help you with the CCS compiler and hardware problems, they don't want to waste time on the Proteus simulator.
Quote: | did exactly that, but didn't work | This doesn't prove to me that you did it right.
1) Please post your latest software with the fixes. Also make your program a lot smaller. Get rid of all the stuff that has nothing to do with the I2C communications problem.
2) How do you know the first I2C command is working and the second is failing? In your master program nothing is done with the result of the I2C commands.
3) ALWAYS post your compiler version number and whether you are testing in real hardware or simulation! |
|
|
semmoor
Joined: 09 May 2012 Posts: 46 Location: KSA
|
|
Posted: Wed Jul 25, 2012 4:42 am |
|
|
ckielstra wrote: | You mentioned the bad P word!
At least 80% of the people on this forum will now stop reading.
Years ago I did play a bit with Proteus and it is quick to connect parts together, but when you run into problems you will find it is difficult to use and is full of bugs. People on this forum want to help you with the CCS compiler and hardware problems, they don't want to waste time on the Proteus simulator.
Quote: | did exactly that, but didn't work | This doesn't prove to me that you did it right.
1) Please post your latest software with the fixes. Also make your program a lot smaller. Get rid of all the stuff that has nothing to do with the I2C communications problem.
2) How do you know the first I2C command is working and the second is failing? In your master program nothing is done with the result of the I2C commands.
3) ALWAYS post your compiler version number and whether you are testing in real hardware or simulation! |
sorry i was busy my friend, i did what i told you last time and i will post
the code.
this is the master:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//#use i2c(Master, sda=PIN_C4, scl=PIN_C3) //not used !
#define SLAVE_WRT_ADDR 0x14
#define SLAVE_READ_ADDR 0x15
#include "input.c"
#include "2416.c"
int8 data_from_slave=0x00;
//Example_3, send 's' and 'r' to turn on LEDs in Slave PIC
//and receive data from slave to be stored in eeprom and read it from eeprom to turn on LEDs on Master PIC.
main()
{
init_ext_eeprom(); //i used this for initiallizing i2c since the eeporm uses this for i2c
//now read data from slave
i2c_start();
i2c_write(SLAVE_READ_ADDR);
data_from_slave = i2c_read(0);
i2c_stop();
//below code turns on LEDs by reading eeporm stored value
printf("Start\n\r\n\r");
write_ext_eeprom(000, data_from_slave); //write 0xF0 from slave
printf("I Wrote 0xF0 to eeprom address 0\n\r");
printf("This is the stord value %X\n\r", read_ext_eeprom(000));
printf("LEDs should be ON corresponding to eeprom stored value\n\r"); output_b(read_ext_eeprom(000));
delay_ms(1000);
//now send 's' and 'r' to turn on and off LEDs on the slave, ! this is the //problem
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('s');
i2c_stop(); delay_ms(1000);
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('r');
i2c_stop(); delay_ms(1000);
printf("\n\rDone\n\r");
while(1);
}
|
slave code:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0x14)
int8 incoming = 0, state;
BYTE address, buffer[0x10];
#INT_SSP
void ssp_isr(void)
{
state = i2c_isr_state();
if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) // Master is requesting data from slave
{
i2c_write(0xf0);
}
switch(incoming) //test value sent by master
{
case 's':
output_d(0xff);
break;
case 'r':
output_d(0x00);
//write_ext_eeprom(000, 0xFF);
break;
}
}
void main ()
{
setup_adc_ports(NO_ANALOGS);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(1)
{
}
}
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jul 25, 2012 7:16 am |
|
|
RF_Developer wrote: | You have read 2416.c, haven't you?
It has its own use i2c, and it defaults to pin E0 for SDA and E1 for SCL. If you want to override those settings you must define EEPROM_SDA before including 2416.c.
Code: |
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#include "2416.c"
|
| Where is this in your Master program?
Minor issue, you have a compiler warning in the Master program for 'void' missing in the main declaration:
I asked you to make both programs smaller. Now there is code reading and writing to the external EEPROM which most likely has nothing to do with your problem. Get rid of it. Now it is only confusing the problem and wastes our time in analysing unrelated code.
Same for the Slave where you have dubious code in the interrupt handler for receiving an address that the Master is never sending.
My questions 2 and 3 haven't been answered as well....
Why would I spend time to your problem if you don't take me seriously? |
|
|
semmoor
Joined: 09 May 2012 Posts: 46 Location: KSA
|
it worked. |
Posted: Thu Jul 26, 2012 4:06 am |
|
|
ckielstra wrote: | RF_Developer wrote: | You have read 2416.c, haven't you?
It has its own use i2c, and it defaults to pin E0 for SDA and E1 for SCL. If you want to override those settings you must define EEPROM_SDA before including 2416.c.
Code: |
#define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
#include "2416.c"
|
| Where is this in your Master program?
Minor issue, you have a compiler warning in the Master program for 'void' missing in the main declaration:
I asked you to make both programs smaller. Now there is code reading and writing to the external EEPROM which most likely has nothing to do with your problem. Get rid of it. Now it is only confusing the problem and wastes our time in analysing unrelated code.
Same for the Slave where you have dubious code in the interrupt handler for receiving an address that the Master is never sending.
My questions 2 and 3 haven't been answered as well....
Why would I spend time to your problem if you don't take me seriously? |
i'm very sorry about that ckielstra.
i removed the external eeprom code and i added
these #define EEPROM_SDA PIN_C4
#define EEPROM_SCL PIN_C3
it worked ! and this is the master:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define EEPROM_SDA PIN_E0
#define EEPROM_SCL PIN_E1
#define SLAVE_WRT_ADDR 0x14
#define SLAVE_READ_ADDR 0x15
#include "input.c"
#include "2416.c"
void main()
{
init_ext_eeprom();
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('s');
i2c_stop(); delay_ms(1000);
i2c_start();
i2c_write(SLAVE_WRT_ADDR);
i2c_write('r');
i2c_stop(); delay_ms(1000);
while(1);
}
|
slave code:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0x14)
int8 incoming = 0, state;
BYTE address, buffer[0x10];
#INT_SSP
void ssp_isr(void)
{
state = i2c_isr_state();
if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
switch(incoming) //test value sent by master
{
case 's':
output_d(0xff); turn on leds
break;
case 'r':
output_d(0x00); //turn off leds
break;
}
}
void main ()
{
setup_adc_ports(NO_ANALOGS);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(1)
{
}
}
|
this sends data from master to slave successfully.
thanks ckielstra.
but what if i want to add the code for the external eeprom with this program??
for example: when slave sends data to master, master reads it and sends it to external eeprom.
i tried to add this with my code but never worked !
if i comment out the code for eeprom, it works fine like the above last code i posted.
and if i comment out the code above and only keep the eeprom it works, so i can understand that this program only works with one specific command!!!
i know i'm wrong ! but that's what i see.
anyway, thank you again ckielstra , and others who helped me. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Jul 27, 2012 1:57 pm |
|
|
Without actual code I can't say where you went wrong. You do have all the pieces of the puzzle and we have proven every single part to be working. Somewhere in sticking the pieces together you make an error.
My suggestion is to expand your program in small pieces. When the program is not behaving as expected you know it is in the just added piece.
For example:
- Add in the master code to read and write to the EEPROM, including a simple test to prove it is working.
- Add in the slave the code to send back a known response over I2C.
- In the master check the received (known) code from the slave.
- Now make it more flexible by having the master ask a variable answer and check for a correct slave response.
- Add code to write the slave response to the slave.
Just one last remark: Code: | if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
} | This part is tricky as you are not testing the address received in the second byte to be within range. Just assuming you are sending the value 'r' then this equals to ASCII value 114, well beyond the range of your 0x10 byte buffer. It causes buffer overflow problems where unknown other variables in RAM will be overwritten. Disaster follows. |
|
|
semmoor
Joined: 09 May 2012 Posts: 46 Location: KSA
|
|
Posted: Tue Jul 31, 2012 5:21 am |
|
|
hi guys how's everybody.
i just have a few questions about pin change interrupts.
i'm using a program that detects pin change interrupts on B4-B7 actually when a button is pressed, i modified it and it works 100% when switch on B4 is pressed it blinks led on D0 and when B5 is pressed it blinks led ob D1 and so on, ! but i don't how??
this is the code:
Code: |
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//this the isr, this will be entered when pin change interrupt on B4-B7 occures
#int_rb
void detect_rb_change() {
int current;
static int last=0;
set_tris_b(0xF0); //B4-B7 as input to detect interrupt change
current=input_b(); //current gets the current click on port b
if ((!bit_test(current,4)) &&(bit_test(last,4))) //if B4 is low(pressed) and now high(released), ! not sure about the comments just wrote it
{
output_high(PIN_D0); //turn on led on D0
}
else //otherwise
{
if ((bit_test(current,4)) &&(!bit_test(last,4))) //if B4 is //high(released) and now last is low ! not sure about the comments just wrote it
output_low(PIN_D0); //turn off led on D0
}
//the same for below but for B5-B7
if ((!bit_test(current,5))&&(bit_test(last,5)))
{
output_high(PIN_D1);
}
else
{
if ((bit_test(current,5))&&(!bit_test(last,5)))
output_low(PIN_D1);
}
if((!bit_test(current,6))&&(bit_test(last,6)))
{
output_high(PIN_D2);
}
else
{
if((bit_test(current,6))&&(!bit_test(last,6)))
output_low(PIN_D2);
}
if((!bit_test(current,7))&&(bit_test(last,7)))
{
output_high(PIN_D3);
}
else
{
if((bit_test(current,7))&&(!bit_test(last,7)))
output_low(PIN_D3);
}
last=current; //last will get the current click
}
void main() {
enable_interrupts(INT_RB); //enabling port b pin change interrupt
enable_interrupts(GLOBAL); //enabling global interrupts
while (TRUE)
{
//
}
}
|
i did not understand the bit_test function i read the help page on CCS but i didn't really get it.
and by the way can i put the sleep inside the endless loop i.e:
Code: |
void main() {
enable_interrupts(INT_RB); //enabling port b pin change interrupt
enable_interrupts(GLOBAL); //enabling global interrupts
while (TRUE)
{
sleep(); //here
}
}
|
so the pic will be in sleep mode unless a pin change interrupt is detected.[/code] |
|
|
|
|
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
|