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

I2C Communication problems between 2 PIC's
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 13, 2007 1:02 pm     Reply with quote

There are several threads on this. Here's one of them:
http://www.ccsinfo.com/forum/viewtopic.php?t=24074&highlight=float+union


This CCS FAQ article has some code to split a float.
http://www.ccsinfo.com/faq.php?page=write_eeprom_not_byte
Unfortunately, it's no longer functional after vs. 4.021, where
they made this change:
Quote:
4.021 The & unary operator by default no longer returns a generic (int8 *)


To fix it, you have to cast the address of the floating point data
to a byte pointer, as shown in bold below.
Quote:

WRITE_FLOAT_EXT_EEPROM(long int n, float data) {
int i;

for (i = 0; i < 4; i++)
write_ext_eeprom(i + n, *((int8*)&data + i) ) ;
}

float READ_FLOAT_EXT_EEPROM(long int n) {
int i;
float data;

for (i = 0; i < 4; i++)
*((int8*)&data + i) = read_ext_eeprom(i + n);

return(data);
}
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 7:05 am     Reply with quote

OK, so I attempted to apply that to what I am doing with the I2C communications between the PICs. I am just trying to see if it works by sending a 1 and seeing what it sends back. I recieve a -.000000 and don't know why. I assume it has something to do with how I am pointing to the memory locations to send them and then reading them. I will post the code I have now, but be advised, I have sections commented out that are about converting 32 bit ints to 8 bit and sending them, but this does not work with floats. If someone with more expertise in the pointer field could give me a hand, I would appreciate it. And by the way, thank you PCM Programmer for your help so far.

Code:
#include <18F452.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, SDA=PIN_C4, SCL=PIN_C3)

//====================================
/*
I2C_WRITE_FLOAT(long int n, float data) {
int i;

i = 0;
i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x00);// Low byte of command
i2c_write((int8*)&data + i)); // High byte of command
i2c_stop();     // Stop condition

i = 1;
i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop();     // Stop condition

i=2;
i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x02);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop();     // Stop condition

i=3;
i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x03);// Low byte of command
i2c_write(*((int8*)&data + i) )); // High byte of command
i2c_stop();     // Stop condition

}
//-------------------------------------
float READ_FLOAT_EXT_EEPROM(long int n) {
int i;
float data;

for (i = 0; i < 4; i++)
*((int8*)&data + i) = read_ext_eeprom(i + n);

return(data);
}
*/
//=====================================

void main()
{
//int8 f0, f1, f2, f3, g0, g1, g2, g3; //int8 for int32 conversion
int8 data_1;
float i, data, data_read;
char j;

data=1;
j='Z';
while(1){

/*//Convert 32 bit int to 1 byte ints.
f3 = MAKE8(i,3);
f2 = make8(i,2);
f1 = make8(i,1);
f0 = make8(i,0);
*/

// Write float to the slave 1 board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write(*(&data+0));
i2c_write(0x01);
i2c_write(*(&data+1));
i2c_write(0x02);
i2c_write(*(&data+2));
i2c_write(0x03);
i2c_write(*(&data+3));
i2c_stop();
delay_ms(200);

//Write to the slave 2 board.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_write(j);
i2c_stop();
delay_ms(200);

// Read float bytes from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read(0);
*(&data_read+1) = i2c_read(1);
*(&data_read+2) = i2c_read(2);
*(&data_read+3) = i2c_read(3);
i2c_stop();
//data_1=make32(g0, g1, g2, g3); For reassembling int32
printf("read from 1: %f \n\r", data_read); //also tried %c and %f
delay_ms (200);

//Read from the slave 2 board and display the data.
i2c_start();
i2c_write(0xB0);
i2c_write(0x00);
i2c_start();
i2c_write(0xB1);
data_1 = i2c_read(0);
i2c_stop();
printf("read from 2: %c \n\r\n\r", data_1);
delay_ms (200);


//i=i+1;
j--;
}
}

Thank you
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 11:37 am     Reply with quote

Quote:
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read(0);
*(&data_read+1) = i2c_read(1);
*(&data_read+2) = i2c_read(2);
*(&data_read+3) = i2c_read(3);
i2c_stop();

This is not the correct way to read sequential bytes. The i2c_read()
function doesn't take an address. The parameter can be either a
0 or a 1.

1 -- means to do an "ACK". (acknowledge)
0 -- means to do a "NAK" (no acknowledge)

In the i2c protocol, the last read operation must do a NAK.
The read operations prior to the last one must do ACKs.

Also, to do an ACK, you don't have to supply the 1. It's understood
to be a 1 if you don't put in a parameter.

So delete all the parameters in that group of four i2c_read() statements,
except for the last one, and give it a parameter of 0.
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 12:26 pm     Reply with quote

OK, so here is the story. I tried to take the numbers out and put only a zero in the last i2c_read, but now the program just freezes and does not output anything. I did research this a bit, and tried to use the i2c_poll function with no success. Here is the modified section of code I tried with no luck:

Code:
// Read float bytes from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
*(&data_read+0) = i2c_read();
*(&data_read+1) = i2c_read();
*(&data_read+2) = i2c_read();
*(&data_read+3) = i2c_read(0);
i2c_stop();
printf("read from 1: %f \n\r", data_read); //also tried %c and %f
delay_ms (200);
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 12:36 pm     Reply with quote

What I would do is:

1. Forget trying to send and receive floats (for now).
Get it working with just sending, receiving, and displaying
four sequential bytes (such as 0x01, 0x02, 0x03, 0x04).
Don't even involve floats in any way in the testing.

2. Don't add tests to talk to a 2nd Slave PIC when the primary
problem hasn't been solved yet. Remove all code that talks
to the 2nd slave and remove the hardware for the 2nd slave.

Strip everything down to essentials and solve the main problem.
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 12:48 pm     Reply with quote

Is the method I'm using to write the data correct?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 12:56 pm     Reply with quote

Now that I look at it, I can say that the CCS Ex_slave.c example
has no ability to receive or send more than one data byte per
i2c operation. If you look at the #int_ssp isr code, you can see
that there is no code to ever increment the 'address' variable.
So despite the comments in that file, it doesn't really completely
emulate the 24LC01 eeprom. You can't do sequential reads or
writes of more than 1 byte.

So your code will have be modified.
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

Update
PostPosted: Thu Mar 15, 2007 1:19 pm     Reply with quote

OK, here is the story. I skimmed this down to next to nothing, and it still doesnt work when trying to send multiple bits. When I comment out the sections making the program send more than one byte, it works properly. Once I add the multiple byte section, the program freezes. I placed a printf after the write section, with the multiple byte writing, and it gets that far. Once the program gets to the reading multiple bytes, it holds up. I will post the program with the commented out sections. This version works to transmit one byte, but once you take the comments out and change the first i2c_read(0) to i2c_read(), the program freezes. Here is the code, it may help to copy and paste it into a compiler program to visualize the comments with color. Thank you.

Code:
#include <18F452.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, SDA=PIN_C4, SCL=PIN_C3)

//====================================

void main()
{
int8 f0, f1, f2, f3, g0, g1, g2, g3;

f0=1;
f1=2;
f2=3;
f3=4;

 
while(1){
// Write float to the slave 1 board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write(f0);
/*i2c_write(0x01);
i2c_write(f1);
i2c_write(0x02);
i2c_write(f2);
i2c_write(0x03);
i2c_write(f3);
i2c_stop();
delay_ms(200);
printf("Written.\n\r");*/

// Read float bytes from the slave 1 board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
g0 = i2c_read(0);
/*g1 = i2c_read();
g2 = i2c_read();
g3 = i2c_read(0); */
i2c_stop();
printf("read from 1: %d \n\r", g0);
//printf("read from 1: %d %d %d %d \n\r", g0, g1, g2, g3);
delay_ms (200);
}
}
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 1:22 pm     Reply with quote

Sorry, I missed your last post. It appears that this has become even more complicated... I'll re-examine this to see if it is worth the re-writing of the EX_SLAVE.c program. If you have any easy modifications for that, pleease post. If it is too complicated, don't waste your time, at least not yet. I thank you for your help, it would have taken me a lot longer to discover that. I am glad you take the time to help people like me out, I do appreciate it.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 1:28 pm     Reply with quote

Try doing it with four totally separate write sequences, each writing
only one byte, and each with it's own i2c start and stop statements.

Do the same thing for read.
bestbuylvr



Joined: 31 Jan 2007
Posts: 27
Location: Pittsburgh, PA

View user's profile Send private message

PostPosted: Mon Mar 19, 2007 7:28 am     Reply with quote

I tried the separate write sequence idea, but the program just seems to freeze up every time after the write process. Does anyone know of an existing I2C Slave program capable of writing and reading to and from different address locations?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Mar 19, 2007 3:04 pm     Reply with quote

I made a test program for the i2c Master PIC, and it works OK.
It can successfully write and read four floating point numbers to
a PIC which is running the CCS Ex_Slave.c program.

Here is the output from the program below, as displayed on
a terminal window on my PC:
Quote:

addr = 0, value = 1.234560
addr = 4, value = 4.567890
addr = 8, value = 3.141590
addr = 12, value = 2.718280


Put this program into the Master PIC. Connect it to another
PIC which is running Ex_Slave.c. Be sure to use pull-up resistors
on the SDA and SCL lines. Also connect a ground wire between
the two boards.
Code:

#include <16F877.H>
#fuses XT, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

// Use the CCS driver for a 24LC01 eeprom to provide the
// low level i2c read and write routines which will talk
// to the PIC that is running the Ex_Slave.c program.
#include <2401.c>

// The following two routines come from the CCS FAQ page:
http://www.ccsinfo.com/faq.php?page=write_eeprom_not_byte

//---------------------------------------------------
void write_float_to_ext_eeprom(long int n, float data)
{
int i;

for(i = 0; i < 4; i++)
    write_ext_eeprom(i + n, *((int8*)&data + i) ) ;
}

//------------------------------------
float read_float_ext_eeprom(long int n)
{
int i;
float data;

for(i = 0; i < 4; i++)
    *((int8*)&data + i) = read_ext_eeprom(i + n);

return(data);
}


//===============================

void main()
{
int8 i;
float value;
float result;
int8 addr;   

// Write four floating point numbers
// to the "eeprom" in a PIC that is
// running the Ex_Slave.c program.
// Each floating point number will take
// four bytes in the "eeprom", so the
// address must be advanced by 4 for
// each new value that is written to
// "eeprom".   Also, the Ex_Slave.c
// program only has a 16-byte array
// to store the data.  So only four
// floats can be written to it.

value = 1.23456;
write_float_to_ext_eeprom(0, value);

value = 4.56789;
write_float_to_ext_eeprom(4, value);

value = 3.14159;
write_float_to_ext_eeprom(8, value);

value = 2.71828;
write_float_to_ext_eeprom(12, value);

// Now read the floating point numbers
// from the Ex_Slave PIC and display them.
addr = 0;
for(i = 0; i < 4; i++)
   {
    result = read_float_ext_eeprom(addr);
 
    printf("addr = %lu, value = %f \n\r" , addr, result);

    addr += 4;
   }

while(1);
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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