CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

PIC, I2C, EEPROM, PROBLEM

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PIC, I2C, EEPROM, PROBLEM
PostPosted: Mon Jul 23, 2012 6:01 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 23, 2012 6:32 am     Reply with quote

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: 9188
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 23, 2012 7:15 am     Reply with quote

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

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Mon Jul 23, 2012 11:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jul 24, 2012 3:35 am     Reply with quote

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

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Wed Jul 25, 2012 4:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jul 25, 2012 7:16 am     Reply with quote

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:
Code:
void main()


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

View user's profile Send private message Send e-mail MSN Messenger

it worked.
PostPosted: Thu Jul 26, 2012 4:06 am     Reply with quote

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:
Code:
void main()


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

View user's profile Send private message

PostPosted: Fri Jul 27, 2012 1:57 pm     Reply with quote

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

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Tue Jul 31, 2012 5:21 am     Reply with quote

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?? Very Happy Very Happy

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]
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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