|
|
View previous topic :: View next topic |
Author |
Message |
Jason Guest
|
bus collision on I2C multi slave |
Posted: Fri May 19, 2006 4:08 am |
|
|
I have connected 3 PIC16F877 together with 1 master and 2 slave mode.
The I2C communication worked if only 1 slave PIC was connected. But it failed to start I2C communication if 2 slave PIC was connected.
I have checked the assemby code, the BCLIF bit was HIGH that a bus collision has occured in SSP when configured for I2C Master mode.
Could anybody tell me how to configure this problem? |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri May 19, 2006 8:34 am |
|
|
Make sure you have assigned a different address to each Slave. If you, accidentally, programmed the same address in each Slave then they will fight each other.
Try placing small delays between each i2c command that the Master is sending. If your Slave doesn't have enough time to service the routine before the Master sends the next command it will puke.
I suggest, first, simply having the Master send an i2c_start(), i2c_write(), with the appropriate address, and an i2c_stop() to make sure you are getting an ACK from the Slave. Try alternating the Slave addresses to make sure you can talk to each one. Then, start adding more commands. The i2c_write() returns the ACK bit so you can do something like:
variable = i2c_write(0x90);
and then evaluate the variable to see if the Slave ACK'd or NOACK'd back. Having a scope hooked up really helps a lot too.
Ronald |
|
|
jason Guest
|
|
Posted: Fri May 19, 2006 8:44 am |
|
|
thanks.
but I have already used different slave address. The master code just loop in the I2C_start() instruction.
here is the master code
void main()
{
output_float(SCL); // Float the SCL and SDA lines for the proper operation of I2C
output_float(SDA);
I2C_Data_Tx = 0x0A; // Put ASCII code of 3 in the I2C transmit variable
while(1)
{
i2c_start(); i2c_write(0x81); // Transmit the Address of the Slave Module
I2C_Data_Tx=i2c_read(); // Receive the Data
i2c_stop(); // I2C Stop Condition
output_b(I2C_Data_Tx);
i2c_start(); // I2C Start Condition
i2c_write(0x80); // Transmit the Address of the Slave Module
i2c_write(I2C_Data_Tx); // Transmit the Data
i2c_stop(); // I2C Stop Condition
}
} |
|
|
Ttelmah Guest
|
|
Posted: Fri May 19, 2006 2:23 pm |
|
|
Show the slave code.
What are the addresses of the devices?.
Best Wishes |
|
|
Ttelmah Guest
|
|
Posted: Fri May 19, 2006 3:06 pm |
|
|
The 'key' is to understand that BCLIF, is a slave problem, not a master problem. The master will set this bit, if the SDA line, does not match what it expects when it drives the line. Hence the need to see the slave code, not the master code.
As one comment, what are the values of the pull up resistors you are using?. The extra loading of two devices, may require these to be smaller than on a simpler setup.
There is also a potential problem in the first transaction, in that the master must allow enough time between sending the start, and the address, for the slave to have got the data ready, and loaded it into the output register, _before_ starting to read. Normally, the master should also 'NACK' the last byte received.
Best Wishes |
|
|
Jason Guest
|
|
Posted: Sun May 21, 2006 2:57 am |
|
|
Thanks for your concern. Here is my slave codes....
The pull up resistor I used is 10k ohm
SLAVE CODE (SEND)
#include <16F877.H>
// Standard Configuration "DO NOT CHANGE"
// Device Configuration bits
#fuses HS,NOWDT,NOPUT,NOBROWNOUT,NOLVP,NOPROTECT
#use delay(clock=20000000)
// I2C Slave mode configuration using hardware I2C Module
#use I2C(slave,sda=PIN_C4,scl=PIN_C3,address = 0x81,FORCE_HW)
typedef enum {NOTHING, CONTROL_READ,
ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;
I2C_STATE fState;
BYTE address, buffer[0x10];
#define SCL PIN_C3
#define SDA PIN_C4
// I2C Transmit data variable
byte I2C_Data_Rx,value;
// SSP Interrupt Service for I2C Slave Module Reception
#INT_SSP
void I2C_Recieve()
{
BYTE incoming;
output_b(0x00);
if (i2c_poll() == FALSE) {
i2c_write (value);
fState = NOTHING;
}
else { // a received byte in the buffer
incoming = i2c_read(1);
if (fState == NOTHING){ //internal address,N, in peripheral
fState = CONTROL_READ; //get address
}
else if (fState == CONTROL_READ) {
address = incoming;
fState = ADDRESS_READ;
}
else if (fState == ADDRESS_READ) {
address = incoming;
fState = READ_COMMAND_READ;
}
else if (fState == READ_COMMAND_READ) {
I2C_Data_Rx = incoming;
fState = NOTHING;
}
}
}
void main()
{
output_float(SCL); // Float the SCL and SDA lines for the proper operation of I2C
output_float(SDA);
enable_interrupts(GLOBAL); // Enable Interrupts
enable_interrupts(INT_SSP); // Enable SSP interrupt for I2C Reception
set_tris_d(0xff); //set port d as input
while(1)
{
value = input_d();
// value =10;
}
}
SLAVE CODE (RECEIVE)
#include <16F877.H>
// Standard Configuration "DO NOT CHANGE"
// Device Configuration bits
#fuses HS,NOWDT,NOPUT,NOBROWNOUT,NOLVP,NOPROTECT
#use delay(clock=20000000)
// I2C Slave mode configuration using hardware I2C Module
#use I2C(slave,sda=PIN_C4,scl=PIN_C3,address = 0x81,FORCE_HW)
typedef enum {NOTHING, CONTROL_READ,
ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;
I2C_STATE fState;
BYTE address, buffer[0x10];
#define SCL PIN_C3
#define SDA PIN_C4
// I2C Transmit data variable
byte I2C_Data_Rx,value;
// SSP Interrupt Service for I2C Slave Module Reception
#INT_SSP
void I2C_Recieve()
{
BYTE incoming;
output_b(0x00);
if (i2c_poll() == FALSE) {
i2c_write (value);
fState = NOTHING;
}
else { // a received byte in the buffer
incoming = i2c_read(1);
if (fState == NOTHING){ //internal address,N, in peripheral
fState = CONTROL_READ; //get address
}
else if (fState == CONTROL_READ) {
address = incoming;
fState = ADDRESS_READ;
}
else if (fState == ADDRESS_READ) {
address = incoming;
fState = READ_COMMAND_READ;
}
else if (fState == READ_COMMAND_READ) {
I2C_Data_Rx = incoming;
fState = NOTHING;
}
}
}
void main()
{
output_float(SCL); // Float the SCL and SDA lines for the proper operation of I2C
output_float(SDA);
enable_interrupts(GLOBAL); // Enable Interrupts
enable_interrupts(INT_SSP); // Enable SSP interrupt for I2C Reception
output_b(0x01);
while(1)
{
if(I2C_Data_Rx != 0x00)
{
output_b(I2C_Data_Rx); //Put the received data on PORTB
I2C_Data_Rx = 0x00; // Reinitialize the I2C Receive variable
}
} |
|
|
Jason Guest
|
|
Posted: Sun May 21, 2006 3:55 am |
|
|
The address for SLAVE CODE (RECEIVE) should be 80 |
|
|
Ttelmah Guest
|
|
Posted: Sun May 21, 2006 4:07 am |
|
|
Straight away, problem.
80, and 81, are the _same_address. The address on I2C, occupies the top seven bits of the byte. The bottom bit is the 'direction control' bit. You cannot have a device on '80', and another device on '81', they will _both_ respond to the same address, since they will only look at the top seven bits, before acknowledging.
10K is rather high. This imposes a maximum bus capacitance of 75pF, which you might easily be exceeding. I'd suggest something between 2.2K, and 4.7K.
Best Wishes |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Mon May 22, 2006 9:34 am |
|
|
Slave addresses can only be even adresses. This is because the LSB is used to determine the direction of the data being sent/received.
Say, you have a Slave with an address of 0x90. If the Master sends an address of 0x90 then the Master is going to be sending data to the Slave. If the Master sends an address of 0x91 then the Master is going to be retrieving data from the Slave. This could be a source of your problem. Try assigning the Slave to address 0x80. The next valid address would be 0x82. The Master would then use addresses 0x82 and 0x83 for sending and retrieving data, respectivly.
Make sure you have pullups on Both the SDA and SCL lines.
Ronald |
|
|
Jason Guest
|
|
Posted: Tue May 23, 2006 6:10 am |
|
|
Thanks.
I have changed the pull up resistor to 3.3k ohm and the addresses were 0x81 for sending slave address and 0x70 as receiving slave address.
I have put a 10us delay between those I2C statements.
The master PIC and receive the data from the slave address, but the receiving slave pic can not receive the data form the master PIC.
When I run the program in debug mode, the problem is that the master program loop in the second I2C_start() statement. if I press the reset button on sending slave pic, it starts to transfer data to receiving slave pic. |
|
|
Ttelmah Guest
|
|
Posted: Tue May 23, 2006 6:34 am |
|
|
The addresses, must be even. The address only occupies the top 7 bits of the value. A device at address '0x90', will respond to accesses on both 0x90, and 0x91. An access to 0x91, will have the 'read' bit set. Use the hardware status bits, rather than trying to 'guess' what is happening. As it stands, if the slave state machine gets out of sync with the master, responses will be silly. This is why there are the status bits in the peripheral, and/or the I2C_ISR_STATE function to access these. Even 10uSec, is 'borderline'. There are typically something over 30 instructions involved in the int_global handler to actually 'get' to he interrupt handler, plus the extra code inside this before the value is sent.
Best Wishes |
|
|
Jason Guest
|
|
Posted: Tue May 30, 2006 4:28 am |
|
|
Thanks.
The I2C_start() problem is solved. It can send and send and receive data continuously.
But, the I2C master code always receive 0xFF from slave. I have checked and run the slave program in debug mode. The value it sends is 0xF8.
It is strange that sometimes the master code can receive 0xF8, but most of the time receives 0xFF.
How can I fix this problem? |
|
|
|
|
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
|