![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Chad.Klippert
Joined: 06 May 2005 Posts: 4
|
I2C troubles between two 18LF6627s |
Posted: Mon Oct 01, 2007 6:49 pm |
|
|
Hi,
I've been trying to get a comms interface working between two PIC18LF6627s. I'm working with a master/slave configuration and have found plenty of instructions on how to set up the master code, but not he slave code. Both chips are running at 3.3V. I have about 6 inches of copper between the chips, and the only other components on the I2C bus are two 16LC256 chips. The I2C works perfectly to the EEPROM chips so I don't think there is anything awry with my hardware setup. I initially had 4.7K pullups but recently tried decreasing the value to 2K for the pullups to see if that would make a difference (I had noted significant slew on the signals)... this change didn't help.
I have a snippet from my actual communications routines below... any help/suggestions are much appreciated. I've tries scouring the forums looking for anything that is similar to my problem but the only threads I've found aren't quite what I'm looking for. I've added all of the hooks below due to the interface not working.
Code: |
// Master code
#use i2c(master,sda=I2C_SDA, scl=I2C_SCL,FAST,FORCE_HW,RESTART_WDT)
void I2CDiscovery(void)
{
int i;
int Rcvd_char;
Rcvd_char = 0;
fprintf(SP, "Performing Peripheral Discovery...\r\n");
fprintf(SP, "Attempt");
for (i=1;i<=5;i++)
{
fprintf(SP, "...%u ", i);
if (!PERIPH_PRESENT)
{
i2c_start();
delay_ms(5);
if (!i2c_write(PERIPH_WADDR))
{
delay_ms(5);
if (!i2c_write(I2C_DISC_REQ))
{
delay_ms(5);
i2c_start();
delay_ms(10);
if (!i2c_write(PERIPH_RADDR))
{
delay_ms(5);
Rcvd_char = (int)i2c_read();
delay_ms(5);
i2c_stop();
if (Rcvd_char)
{
PERIPH_PRESENT = TRUE;
PERIPH_Version = Rcvd_char;
break;
}
else
{
delay_ms(500);
}
}
else
{
i2c_stop();
delay_ms(500);
}
}
else
{
i2c_stop();
delay_ms(500);
}
}
else
{
i2c_stop();
delay_ms(500);
}
}
else
break;
}
fprintf(SP,"\r\n");
if (PERIPH_PRESENT)
{
fprintf(SP, "Peripheral is present and enabled - F/W Ver. =");
fprintf(SP, "%u\r\n", PERIPH_Version);
}
else
fprintf(SP, "Peripheral not present\r\n");
delay_ms(100);
}
|
================
Code: |
// Slave code:
#use I2C(SLAVE,SDA=PIN_D5,SCL=PIN_D6,address=0x88,FAST,RESTART_WDT,FORCE_HW)
#INT_SSP2
void i2c_interrupt(void)
{
i2c_rcvd = TRUE;
i2c_state = i2c_isr_state();
}
// a tight main routine calls i2c_handler when i2c_rcvd = TRUE
void I2C_Handler(void)
{
char Rcvd_char;
i2c_rcvd=FALSE;
if (i2c_state==0x00)
{
// add anything here?
}
else if (i2c_state==0x01)
{
Rcvd_char=i2c_read();
i2c_command=Rcvd_char;
}
else if (i2c_state==0x80)
{
switch (i2c_command)
{
case I2C_DISC_REQ: // was received byte a discovery request
if (!(i2c_write((int)(FW_Build-30000))))
{
i2c_Discovery=TRUE;
i2c_command=I2C_NO_CMD;
}
break;
case I2C_STAT_REQ:
break;
case I2C_MTRC_REQ:
break;
default:
fprintf(SP,"I2C Command Error: 0x%X\r\n", i2c_command);
break;
}
}
else
{
i2c_write((int)(FW_Build-30000)); // write a dummy byte ???? why is this necessary...??
}
if (i2c_Discovery && !i2c_DiscReported)
{
fprintf(SP, "I2C Discovery complete\r\n");
i2c_DiscReported = TRUE;
}
}
|
==========================================
The behaviour I'm seeing is that when the master attempts to issue the i2c_stop command, the clock line releases, but the data line remains low.
I've tried several permutations of what I think needs to happen here, but the rest of the system essentially hangs after these routines seemingly complete. The firmware version is passed properly between the two chips but that is the only success I've really had with this.
Any ideas?
Chad |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 01, 2007 9:09 pm |
|
|
Test it in Slow mode. Fast mode may not work. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Tue Oct 02, 2007 2:53 am |
|
|
A number of comments.
Get rid of the 'fast' keyword in the slave. The slave does not generate a clock, and this does nothing.
As it stands, you are creating a huge delay, between the interrupt occurring, and potentially the data being read. Why not use the interrupt for what it is designed for, and service the values here?.
Yes, you need to read the character in state 0. The character received here is the address, but it still needs to be read.
In the I2C routines,_all_read transactions, require the character to be read, and _all_ write transactions require a character to be written. You do this in the 'write' with a dummy write (which should never be reached, unless your master reads two bytes), but are not doing this in the read, except for state 1. In fact of you get a state 2 (which should be a read', you will go to the 'write' routine....
You also don't write, if the command byte is 'STAT_REQ', or 'MTRC_REQ'...
Is 'FW_Build-30000', going to be a single byte value?. Otherwise you will not see what you expect.
You are checking the 'ACK' status in the main, but do nothing to change this in the slave. Look at I2C_READ(0), which is needed to develop a NACK. You are also checking NACK in the slave, but the master does nothing to change this...
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Oct 02, 2007 9:32 am |
|
|
You should place your I2C_Handler() code inside of the ISR. Like Ttelmah stated, this is what the ISR is for. The I2C bus needs to be read quickly and by puting the write/read commands in an external function the delays will kill you. You might want to set/clear the CKP bit inside the slave ISR. This will hold the SCK line low and cause the master to pause and enable the slave to do 'it's thing'.
The normal protocol for I2C is for the master to send a NOACK when it's finished with a read sequence. The last read command, sent by the master, should be: i2c_read(0). By default, the i2c_read() command sends a '1' which sends an ACK. The NOACK tells the slave that the master is finished and prepares the slave to stop sending data.
Look at the many posts regarding I2C and slave code. Also, make sure your slave's crystal is fast enough to service the commands that the master is sending. Even though you are placing delays in your master code, if the slave is not running fast enough things will get stuck in the mud.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
Chad.Klippert
Joined: 06 May 2005 Posts: 4
|
|
Posted: Tue Oct 02, 2007 12:18 pm |
|
|
Thanks for all of the input. Lots of suggestions and things I hadn't thought of.
I don't know which of these things (or how many of them) in particular fixed the issue but it's working now after doing:
1. Moved the receive routine into the ISR.
2. Removed the "FAST" from the slave use i2c directive
3. Changed the master call to i2c_read to pass (0)
4. Added a i2c_read for state 0 in the slave
5. Toggling of CKP bit in slave during ISR handling
I suspect that the combination of everything other than 2. above led to it working, so thanks to all. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|