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 Slave addressing Issue

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



Joined: 20 Jul 2006
Posts: 15

View user's profile Send private message

I2C Slave addressing Issue
PostPosted: Sun Oct 15, 2006 2:39 pm     Reply with quote

I am using a PIC18F2520 as a SLAVE in an I2C protocol.


• When the master sends the start command, it succeeds with a command that includes the address of the SLAVE.
• There are two types of data packets the Master is interested in reading from the same SLAVE.
• Is it possible to change the 7th bit logic in the address to tell the slave what data packet it needs.
• I was thinking this may not be possible, since this would cause a change in address of the same slave, which intern would not cause the Interrupt bit to set. Unless there is a way to save two different addresses for the same Slave. This way if either of the address arrives from the Master, the Slave hardware will match it, set the ACK as well as the Interrupt bit!!! Is that true!!
Thanks
Ttelmah
Guest







PostPosted: Sun Oct 15, 2006 3:01 pm     Reply with quote

Not basically possible as you describe, but it can be done, by using GCA. On I2C, the reserved address '00', can also be programmed to trigger the interrupt. There is provision in this, to have the next packet carry configuration data for the slave. So you send '00', '04', 'new address', and the slave is setup to take the third byte, and change it's slave address. This is fully 'legal' I2C. However if the bus is only for your own use, then just send a flag to tell the slave to change modes, using GCA.
However there seems little point in doing it this way. Why not just send the 'flag' using a write, with a higher data address?.
So, assuming the device is at (say) address 24, then:

start
send 24 (data write command)
send '0' to say that we want the first type of packet
send a repeated start
send 25 (data read command)
now read the data

For the second packet type, send:

start
send 24
send '1' to say we want the second packet type
send a repeated start
send 25 (data read command)
now read the data

If you want to be able to address registers in the slave, then instead of sending 0/1, send 'address+0', and 'address+128'. (or an even higher value using two bytes if you support more than 128 useable addresses

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 3:09 pm     Reply with quote

Quote:

There are two types of data packets the Master is interested in reading
from the same SLAVE.

The selection of data to read from the slave is normally done with
the byte (or bytes) that follow after the Device Address byte.

Look at the CCS example, Ex_Slave.c. This example emulates
a 24C00 eeprom, with 16 bytes of data. It's in this folder:
c:\Program Files\Picc\Examples

When the Master wants to read from the PIC that's running the Ex_Slave
code, it can do it by executing this code (in the Master PIC):
BYTE read_ext_eeprom(BYTE address)
{
BYTE data;

while(!ext_eeprom_ready());
i2c_start();
i2c_write(0xa0);
i2c_write(address);
i2c_start();
i2c_write(0xa1);
data=i2c_read(0);
i2c_stop();
return(data);
}

Look at the section of code below, in the Ex_Slave.c #int_ssp isr.
This code in the Slave will be executed when the master does
the "i2c_read(0)" line, shown above. (The address was previously sent
by the "i2c_write(address)" in the Master code).
In the code below, they're just using the address as an index into an
array. But you could do a more complex test (perhaps by checking
individual bit values in the address) and send different data back to the
Master.
Code:

if(state == 0x80)            
   // Master is requesting data
  {
    i2c_write(buffer[address]);
  }
pr83



Joined: 20 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 4:06 pm     Reply with quote

Thanks for the Help.
I have posted another message with my code. I wanted to know if it makes sense!!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 4:14 pm     Reply with quote

You don't have to start a new thread for your code. You can do
a post on this existing thread. You can delete your new post and
post it here.
pr83



Joined: 20 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 4:20 pm     Reply with quote

Thanks for your help. I have 3 conditons in total. I have written code for all it. I wanted to know if I am on the right track.

DECLERATIONS:
Slave Address: 0xa0

CONDITION 1:
The Master is supposed to get 13 bytes(Short Data) of data from the Slave.(SHOWN IN CODE)

CONDITION 2:
The Master is supposed to get 32 bytes(Long Data) of data from the SAME Slave.

? Change in MASTER:
Read Short data to Read Long Data:
i2c_write(10000111); (to) i2c_write(10000101);

? CHANGE IN SLAVE:
In the condition for Master is requesting for data. I will check for
if(command == 10000101)
instead of
if(command == 10000111)

? And I will change both the for loops to iterate 32 times.

CONDITION 3:
The Master is supposed to get 4 bytes of data from the SAME Slave.
The same procedure above!!

Is this method efficient?
Are there some mistakes in the code? Cause the compiler does not seem to like it. Neither does it like my way of writing address.


MASTER (SHORT DATA)
Code:
 
void main()
{

int8 count; // Counter
BYTE ShortBuffer[13]; // Array for incoming Data

i2c_start();
i2c_write(10011100);// Address of the Slave
i2c_write(00000000);

i2c_start();
i2c_write(10000111); // Read Short Data Command
for(count=0;count<13;count++) // Reading 13 bytes from the slave
{
shortBuffer[count] = i2c_read(0);
}
i2c_stop();

}


SLAVE (SHORT DATA)
Code:

BYTE address, command;

#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
int i;

state = i2c_isr_state();

if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address of slave
address = incoming;
if(state == 2) //Second received byte is the coommand the master wants the slave to execute
command = incoming;
}
if(command == 10000111) //Master is requesting short data
{
for(i=0;i<13;i++) // Sending 13 bytes to the master
{
i2c_write(data[i]);
}

}
}

void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);

while (TRUE) {}
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 5:22 pm     Reply with quote

Your interpretation of the i2c_isr_state() values in the Ex_slave.c
example is not correct. Here's what the CCS manual says,
with some additional explanations added:
Code:

Explanation of i2c_isr_state() returned values:

     0 - Address match received with R/W bit clear.
         (For example, slave address of 0xA0)
         This means the Master will be writing data
         to the slave in the next byte (or bytes).

1-0x7F - Master has written data; Call i2c_read()
         immediately in the #int_ssp isr in the Slave
         code, to get the data that was sent by the Master.

  0x80 - Address match received with R/W bit set;
         respond with i2c_write().
         (For example, slave address of 0xA1)
         This means the Master is requesting data from
         the slave.  Call i2c_write() immediately in the
         #int_ssp isr in the Slave code,  to send data
         back to the Master.

0x81-0xFF - Transmission completed and acknowledged;
            respond with i2c_write().   This means the Master
            has received the byte that the Slave sent to it,
            in response to a read operation by the Master.
            The Master has sent an "ACK" bit to the slave
            to show that it successfully got the byte.
            This return code (0x81 to 0xFF) would only occur
            if the Master is doing a read operation.


Here's the main part of the Ex_Slave.c code for #int_ssp.
Notice how the code doesn't save the incoming byte if
the 'state' is 0x00 or 0x80. In other words, the isr code
ignores the Slave Address byte (Either 0xA0 or 0xA1).
It saves the byte which arrives next, after the Slave address.
Code:

state = i2c_isr_state();

if(state < 0x80)   // Master is sending data
  {
   incoming = i2c_read();
   if(state == 1)         // First received byte is address
      address = incoming; //  for a read or write operation.
   if(state == 2)         // Second received byte is data
      buffer[address] = incoming;  // for a write operation.
  }

if(state == 0x80)   // Master is requesting data
  {                            // for a read operation.
   i2c_write(buffer[address]);
  }


In your code, you have put in comments such as:
Quote:
//First received byte is address of slave

But that's not true. The Ex_Slave example (and your code, too)
fetches the Slave address byte, but it just throws it away.
It doesn't need it.

When the slave executes the following code, it's getting your
command byte, not the Slave address.
Code:
if(state == 1)
   address = incoming;


You need to study the Ex_slave code and the chart in the manual
that explains the returned value for i2c_isr_state(). Study it until
you completely understand what the Ex_slave code is doing, for
both a read and a write operation (to the simulated eeprom).
Once you understand every detail, then you can successfully write
your own slave code.
Guest








PostPosted: Sun Oct 15, 2006 8:34 pm     Reply with quote

Dear PCM Programmer,
Thanks for you help. I read the manual. Below is my new understanding for the I2C.

Slave address is 0xA1 or 0xA0.

If the Master writes 0xA1 : Slave needs to call i2c_write so the Master can read.
If the Master writes 0xA0 : Slave needs to call i2c_read so it can read what the Master is writing.

The 0 and 1 are basically clearing and setting the R/W bit.

Code:


MASTER

void main()
{


int8 count; // Counter
BYTE ShortBuffer[13]; // Array for incoming Data
BYTE LongBuffer[32]; // Array for incoming Data

// SHORT DATA

i2c_start();
i2c_write(0xA0);     // Slave address,R/W cleared
i2c_write(0x00);
i2c_write(10000111); // Read Short Data Command

i2c_start();
i2c_write(0xA1); // Slave address,R/W set

for(count=0;count<13;count++) // Reading 13 bytes from the slave
{
shortBuffer[count] = i2c_read(0);
}

i2c_stop();

// LONG DATA

count = 0;

i2c_start();
i2c_write(0xA0);     // Slave address,R/W cleared
i2c_write(0x00);
i2c_write(10000001); // Read Long Data Command

i2c_start();
i2c_write(0xA1); // Slave address,R/W set

for(count=0;count<32;count++) // Reading 32 bytes from the slave
{
LongBuffer[count] = i2c_read(0);
}

i2c_stop();

}







SLAVE

BYTE address, command;

#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
int i;



state = i2c_isr_state();

if(state < 0x80) //Master is sending data
 {
  incoming = i2c_read();
  if(state == 1) // First received byte which will be 00000000
  address = incoming;
  if(state == 2) //Second received byte is the coommand the master wants the slave to execute (10000111 or                                                                                                 10000001).
  command = incoming;
 }
 
if(state == 0x80)   //Master is requesting data
{

  // SHORT DATA

 if(command == 10000111) //Master is requesting short data
 {
    i2c_write(data[0]);// write the first byte to the Master
   
    for(i=1;(i<13);i++) // Sending 13 bytes to the master
    {
     if (0x81<=state<=0xFF) // Check if Master is receiving each byte.
     i2c_write(data[i]);
     }

 }

  // LONG DATA

 if(command == 10000001) //Master is requesting Long data
 {
    i2c_write(dataL[0]);// write the first byte to the Master
   
    for(i=1;(i<32);i++) // Sending 32 bytes to the master
    {
     if (0x81<=state<=0xFF) // Check if Master is receiving each byte.
     i2c_write(dataL[i]);
     }

 }
}
}

void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);

while (TRUE) {}
}



Questions:
1. (MASTER)Why do we always call i2c_write(0x00);
after calling i2c_write(0xA0);

2. (MASTER)Why do we always call i2c_start() second time.

3. In the MASTER and SLAVE I also wrote the code, if I needed the slave to send the 32 byte data packet.

4. I hope the i2c_isr_state() gets reset after the first i2c_stop() in the Master.

Do these seem fine!!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 8:51 pm     Reply with quote

Quote:
if (0x81<=state<=0xFF)

I can't tell, because you didn't disable HTML when you posted the code.
So your post is full of bad statements like the one above.
Also, you logged in as "guest" so you can't edit your post and fix it.

---------------
I don't want you to post code and ask me to approve it.
You should test it, debug it, learn, and make it work.
When you do that, you can give yourself the approval.
pr83



Joined: 20 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 9:14 pm     Reply with quote

OOpppsss!!!
I apologize for that. I have disabled the HTML. I was just wanting to know if my approach is correct.
And if you think I have understood the I2C this time!!

Questions:
1. (MASTER)Why do we always call i2c_write(0x00);
after calling i2c_write(0xA0);

2. (MASTER)Why do we always call i2c_start() second time.

3. In the MASTER and SLAVE I also wrote the code, if I needed the slave to send the 32 byte data packet.

4. I hope the i2c_isr_state() gets reset after the first i2c_stop() in the Master.

Do these seem fine!!

Code:


MASTER

void main()
{


int8 count; // Counter
BYTE ShortBuffer[13]; // Array for incoming Data
BYTE LongBuffer[32]; // Array for incoming Data

// SHORT DATA

i2c_start();
i2c_write(0xA0);     // Slave address,R/W cleared
i2c_write(0x00);
i2c_write(10000111); // Read Short Data Command

i2c_start();
i2c_write(0xA1); // Slave address,R/W set

for(count=0;count<13;count++) // Reading 13 bytes from the slave
{
shortBuffer[count] = i2c_read(0);
}

i2c_stop();

// LONG DATA

count = 0;

i2c_start();
i2c_write(0xA0);     // Slave address,R/W cleared
i2c_write(0x00);
i2c_write(10000001); // Read Long Data Command

i2c_start();
i2c_write(0xA1); // Slave address,R/W set

for(count=0;count<32;count++) // Reading 32 bytes from the slave
{
LongBuffer[count] = i2c_read(0);
}

i2c_stop();

}







SLAVE

BYTE address, command;

#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
int i;



state = i2c_isr_state();

if(state < 0x80) //Master is sending data
 {
  incoming = i2c_read();
  if(state == 1) // First received byte which will be 00000000
  address = incoming;
  if(state == 2) //Second received byte is the coommand the master wants the slave to execute (10000111 or                                                                                                 10000001).
  command = incoming;
 }
 
if(state == 0x80)   //Master is requesting data
{

  // SHORT DATA

 if(command == 10000111) //Master is requesting short data
 {
    i2c_write(data[0]);// write the first byte to the Master
   
    for(i=1;(i<13);i++) // Sending 13 bytes to the master
    {
      if (0x81<state|| state<0xFF) //Check if Master is receiving each byte.
     i2c_write(data[i]);
     }

 }

  // LONG DATA

 if(command == 10000001) //Master is requesting Long data
 {
    i2c_write(dataL[0]);// write the first byte to the Master
   
    for(i=1;(i<32);i++) // Sending 32 bytes to the master
    {
     if (0x81<state|| state<0xFF) // Check if Master is receiving each byte.
     i2c_write(dataL[i]);
     }

 }
}
}

void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);

while (TRUE) {}
}

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 15, 2006 11:44 pm     Reply with quote

Quote:

1. (MASTER)Why do we always call i2c_write(0x00); after calling
i2c_write(0xA0);

The Ex_Slave program emulates a 24C00 eeprom. The protocol
is defined in the eeprom data sheet.
http://ww1.microchip.com/downloads/en/DeviceDoc/21178d.pdf
Look at the sequence of bytes shown in the data sheet.
It will show you the answer.

Quote:

2. (MASTER)Why do we always call i2c_start() second time.

Again, look in the 24C00 data sheet.

Quote:

3. In the MASTER and SLAVE I also wrote the code, if I needed the slave
to send the 32 byte data packet.

Write the code to do that. Then debug and test it.

Quote:

4. I hope the i2c_isr_state() gets reset after the first i2c_stop() in the
Master.

To see when the compiler clears the i2c state variable, look at
the listing file. It will have a file extension of .LST, and it's in
your project directory. Then put in comments to explain what
each line is doing. In the listing below, you can see that the
state variable is cleared whenever the i2c module receives an
address byte. Look in the PIC's data sheet to see the meaning
of each bit in the SSPSTAT register.
Code:

...... state = i2c_isr_state();
0044:  BSF    STATUS.5     // Bank 1
0045:  BTFSC  SSPSTAT.5    // Goto 0047 if Address
0046:  GOTO   04C          // Goto 004C if Data
0047:  BCF    STATUS.5     // Bank 0
0048:  CLRF   @I2C_STATE   // If got Address, clear state var.   
0049:  BTFSC  SSPBUF.0     // Goto 004B if Write
004A:  BSF    @I2C_STATE.7 // If Read, set bit 7 of state var.
Write_operation:
004B:  BSF    STATUS.5     // Bank 1
Got_Data_Byte:
004C:  BCF    STATUS.5     // Bank 0
004D:  MOVF   @I2C_STATE,W // Save state var. in W
004E:  INCF   @I2C_STATE,F // Increment state variable
004F:  MOVWF  state        // Return state variable

*
0099:  MOVLW  03           // Upon program start-up,
009A:  MOVWF  @I2C_STATE   //  init state var. = 0x03
pr83



Joined: 20 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Mon Oct 16, 2006 2:40 pm     Reply with quote

Dear PCM Programmer,
Thanks a ton for the EEPROM data sheet. It was very helpfull.
Rhesus
Guest







About an insctruction you're using...
PostPosted: Fri Oct 27, 2006 7:08 pm     Reply with quote

Hey, I tried to use the i2c_isr_state() directly, though it didn't work. Where is it? Do I need to include a library or maybe it is a special function register in the PIC?. Please let me know where can I find that statement and use it, since i'm having a really tough time with the I2C bus. Currently I'm using PIC18F452 (it has hardware I2C) and CCS PCWH v. 3.225.

Thanx.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 27, 2006 7:46 pm     Reply with quote

Quote:
I tried to use the i2c_isr_state() directly, though it didn't work.
Currently I'm using PIC18F452 (it has hardware I2C) and CCS PCWH v. 3.225.

See this thread, which tells you the version number at which that
function was first available. It also provides a link to code which
emulates the i2c_isr_state() function, in case your version doesn't
support it.
http://www.ccsinfo.com/forum/viewtopic.php?t=26978
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