View previous topic :: View next topic |
Author |
Message |
ritchie
Joined: 13 Sep 2003 Posts: 87
|
Software I2C Implementation |
Posted: Mon May 03, 2004 4:43 pm |
|
|
Hi,
Is it possible to have two I2C channel? One using the MSSP hardware of the PIC and the other using a software based using PortB[5,6] as the SDA and SCL pin for the I2C.
Any suggestions and comments?
Thank u. |
|
|
Guest
|
|
Posted: Mon May 03, 2004 5:08 pm |
|
|
Yes, but not at the same time. The #use i2c statement would need to be changed for each case:
#use i2c(master,sda=PIN_C4,scl=PIN_C3,FORCE_HW)
// do hardware i2c
#use i2c(master,sda=PIN_B5,scl=PIN_B6)
// do software i2c |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue May 04, 2004 9:00 am |
|
|
I've used a 16F87 to be a Slave (using the hardware I2C) while acting as a Master (using bit-banging) to a sensor. It would use software routines to communicate to the sensor and then send that data to a master that was also talking to several other PIC's doing the same thing.
Ronald |
|
|
Guest
|
|
Posted: Tue May 04, 2004 4:56 pm |
|
|
rnielsen wrote: | I've used a 16F87 to be a Slave (using the hardware I2C) while acting as a Master (using bit-banging) to a sensor. It would use software routines to communicate to the sensor and then send that data to a master that was also talking to several other PIC's doing the same thing.
Ronald |
can u share few snippets on this scheme... |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed May 05, 2004 9:15 am |
|
|
Here's a little bit for you. This is the Slave code that is talking to a SHT11 or SHT15 RH/Temperature sensor.
Code: |
#include <16F87.h>
#use i2c(Slave,fast,sda=PIN_B1,scl=PIN_B4,restart_wdt,address=0x90)
#define XSDA PIN_A2 // sensor I2C data line
#define XSCL PIN_A3 // sensor I2C clock line
#int_SSP // I2C interrupt service routine
SSP_isr()
{
int8 data;
static int8 state = 0;
if(SSPOV)// Make sure the buffer has not overflowed
{
data= SSPBUF;
SSPOV=0; // Clear the register
return;
}
if(STOP)
{
return;
}
else
{
switch(SSPSTAT & 0x2D)
{
CASE 0x0C:// Master rx, slave address + 1
CKP = 0;// hold SCL low, stretch it out
index = 0;
SSPBUF = stage[index];
index++;
CKP = 1;
break;
CASE 0x2C:// Master rx, data with /ack
CKP = 0;
SSPBUF = stage[index];
index++;
CKP = 1;
break;
CASE 0x28:// Master rx, data with not /ack
sensor = 1;// enable the routine to read the sensor
status = 1;
break;
default:
break;
}//end of switch()
}// end of else
}// end of SSP interupt
////////////////////////
// inserted into main()
////////////////////////
if(sensor)// time to read the sensor
{
switch(status)
{
CASE 1:
if(send_sense(0x03))// send command to read the Temperature
{
status = 0;
sensor = 0;
if(++hey > 3)// if the sensor is not ACKing set reset bit
{
puked = 1;
hey = 0;
}
}
else
{
status = 2;
}
break;
CASE 2:
if(!input(XSDA)) // we need to wait until the sensor is finished
{ // making it's measurement before we try to get
stemp = read_sense(); // the data from it
status = 3;
}
break;
CASE 3:
if(!send_sense(0x05)) // this is the read command for the RH
{
status = 4;
}
break;
CASE 4:
if(!input(XSDA)) // we need to wait for the same thing as the temp
{
shumid = read_sense();
status = 5;
}
break;
CASE 5:
if((!stemp && !shumid) || (stemp > 0x3FFF || shumid > 0xFFF)) // if the sensor has
{ // wigged out, cycle the power to it
if(pwr++ > 10)
{
puked = 1;
}
cycle_power();
}
else
{
TEMP = calc_temp(stemp);
HUMI = calc_rh(shumid);
stage[0] = (HUMI >> 8) & 0xFF;// storage of data to be sent to Master
stage[1] = HUMI & 0xFF;
pwr = 0;
}
status = 6;
break;
default:
break;
}// end of switch()
}// end of if(sensor)
// SUBROUTINES
////////////////////////////////
void rst_i2c(void) // resets the sensor's I2C bus
{
int8 track;
strt_i2c();
for(track = 0; track < 9; track++)
{
output_high(XSCL);
delay_cycles(2);
output_low(XSCL);
delay_cycles(2);
}
busy = 0;
}// end of rst_i2c()
void strt_i2c(void) // I2C start signal for the sensor. the sensor needs a slightly
{ // different start signal than the standard I2C protocol
output_high(XSCL); // calls for.
delay_cycles(1);
output_low(XSDA);
delay_cycles(1);
output_low(XSCL);
delay_cycles(3);
output_high(XSCL);
delay_cycles(1);
output_high(XSDA);
delay_cycles(1);
output_low(XSCL);
}// end of strt_i2c()
unsigned int1 send_sense(int8 address)
{
unsigned int1 ack;
strt_i2c();
ack = write_i2c(address);
return(ack);
}
unsigned int16 read_sense(void)
{
unsigned int8 value1, value2;
unsigned int16 clipboard;
value1 = read_i2c(1);
value2 = read_i2c(0);
clipboard = make16(value1, value2); // combine the two bytes together
return(clipboard);
}
unsigned int8 read_status(void)
{
unsigned int8 statreg;
statreg = read_i2c(0);
return(statreg);
}
// use pins A0, A6, A7 and B7 to select address
void get_add(void) // possible combinations
{// base address is 0x90 0x90 92 94 96 98 9A 9C 9E A0 A2 BASE:1001 0000
if(input(PIN_A0)) // 0 1 0 1 0 1 0 1 0 1
{
bit_set(SLAVE_ADDR, 1);
}
if(input(PIN_A7))// 0 0 1 1 0 0 1 1 0 0
{
bit_set(SLAVE_ADDR, 2);
}
if(input(PIN_A6))// 0 0 0 0 1 1 1 1 0 0
{
bit_set(SLAVE_ADDR, 3);
}
if(input(PIN_B7))// 0 0 0 0 0 0 0 0 1 1
{
bit_clear(SLAVE_ADDR, 4);
bit_set(SLAVE_ADDR, 5);
}
}// end of get_add()
|
Ronald |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
|
Posted: Thu May 06, 2004 5:14 pm |
|
|
Hi,
I modified the code from this link http://www.ccsinfo.com/wwwboard/messages/725.html for my hardware I2C application. However, in this hardware I2C I use 8 momories for my storage thus, I have no room for additional I2C chip.
But my application needs an I2C based RTC chip like the X1226 and with the dilema I don't have any room for adding the X1226 to the existing hardware I2C setup that my application have.
So, my last option is to implement a software-based I2C using PortB as my data and clock.
My question is: would it be possible to use both hadrware I2C and software I2C taking into consideration that for my hardware I2C I never use the built-in CCS I2C function instead I make my own routines base from the URL link above?
Need your comments and suggestions...
Thanx |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Thu May 06, 2004 5:37 pm |
|
|
I did that once, I used CCS' #use I2C to implement a software I2C, and I tweaked the MSSP registers manually to use the hardware I2C module at the same time.
However the second post on this page offers an easier solution. |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
|
Posted: Thu May 06, 2004 6:26 pm |
|
|
Haplo wrote: | I did that once, I used CCS' #use I2C to implement a software I2C, and I tweaked the MSSP registers manually to use the hardware I2C module at the same time.
However the second post on this page offers an easier solution. |
Got ur point...
My hardware I2C setup use the FRAM chip at a clock of 1Mhz and I don't think the #use i2c by CCS support this clock speed.. maybe it operates at 400K the most.... this is the reason why I opted for a registry tweak for my hardware I2C....
For X1226 is I guess a 100K or 400K clock speed....
Anyway, thank u for the info.... I will try this method... |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Thu May 06, 2004 6:53 pm |
|
|
I may be mistaken, but according to the PIC16F87 datasheet it seems the hardware I2C module of this PIC only supports 100KHz and 400KHz speeds. |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
|
Posted: Thu May 06, 2004 7:04 pm |
|
|
Haplo wrote: | I may be mistaken, but according to the PIC16F87 datasheet it seems the hardware I2C module of this PIC only supports 100KHz and 400KHz speeds. |
I modified the code from the link above for my PIC18F452 microcontroller... this microcontroller supports 1MHz clock for I2C... |
|
|
|