Seaborgium
Joined: 23 Jul 2012 Posts: 14
|
10-bit I2C Communication |
Posted: Thu Jul 26, 2012 2:06 pm |
|
|
I have successful 10-bit I2C communication between a 16LF1503 master and 16F886 slave. I've included the relevant portions here.
Master.c:
Code: | #include <Master.h>
#use i2c(Master, Slow, sda=PIN_C3, scl=PIN_C4, force_sw, stream=module)
//Communicates with a certain 10-bit slave address by delivering a certain
//data address, then returns the received data.
//Addresses are even, like 7-bit addresses: the form is 0x??????????0.
int16 requestData(int16 slaveAddress, unsigned int dataAddress) {
int16 data;
int slaveHigh; //High byte of slave address
int slaveLow; //Low byte of slave address
//Split slave address into low and high byte
slaveHigh = (slaveAddress>>8)&0xFE; //Shift over first 3 bits; clear R/W bit
slaveHigh = slaveHigh|0xF0; //"11110XXX" signifies 10-bit address; add this.
slaveLow = (slaveAddress>>1)&0xFF; //Get lower 8 bits, without R/W bit
//Instruct slave that you wish to write
i2c_start(module);
i2c_write(module, slaveHigh); //High byte
i2c_write(module, slaveLow); //Low byte
//Give data address
i2c_write(module, dataAddress);
//Restart; instruct slave that you wish to read
i2c_start(module);
i2c_write(module, slaveHigh|1); //High byte with R/W set
//Receive data and finish
data=i2c_read(module, 1)<<8; //Read high byte and ACK
data+=i2c_read(module, 0); //Read low byte and end transmission
i2c_stop(module);
return data;
}
void main() {
setup_comparator(NC_NC_NC_NC); // This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(TRUE);
} |
Master.h:
Code: | #include <16LF1503.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES WDT_SW //No Watch Dog Timer, enabled in Software
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(int=16000000) |
Slave.c:
Code: | #include <Slave.h>
//10-bit addressing bits
#BYTE SSPCON=0x14
#BIT SSPM0=SSPCON.0
#BYTE SSPSTAT=0x94
#BIT UPDATEADDR=SSPSTAT.1
#BIT RW=SSPSTAT.2
//Change # of sensors per module to correct number in sensorVals
int writeBuffer [2]; //Holds data to write through i2c
//10-bit addressing stuff
int1 firstByte; //Records whether first byte of 10-bit address has been received
int16 addrHigh; //High byte of address
int16 addrLow; //Low byte of address
#int_SSP
void i2c_interrupt() {
if (UPDATEADDR) { //Just received one of two start bytes
if (!firstByte) { //Just received first byte
firstByte=TRUE;
i2c_slaveAddr(addrLow); //Set low byte
}
else { //Just received second byte
firstByte=FALSE;
i2c_slaveAddr(addrHigh); //Set high byte
}
i2c_read();
return;
}
//Get state
int state;
//Clear R/W bit; CCS compiler sometimes gives incorrect value.
state = i2c_isr_state()&0b01111111;
if (RW==TRUE) //Manually retrieve R/W bit.
state+=0x80;
if (state==0||state==0x80) //Master has issued start command
i2c_read(); //Clear address from read buffer.
if (state>=0x80) //Master is waiting for data
i2c_write(writeBuffer[state - 0x80]); //Write appropriate byte, based on how many have already been written
else if(state>0) { //Master has sent data; read.
unsigned int message;
message=i2c_read();
//Master requests sensor data.
int16 toSend;
toSend=0b10101010;
writeBuffer[0] = toSend>>8;
writeBuffer[1] = toSend&0xFF;
}
}
void main() {
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP); //Enable interrupts
enable_interrupts(GLOBAL);
GCEN=TRUE; //Allow general calls
SSPM0=TRUE; //10-bit addressing
firstByte=FALSE;
int16 slaveAddress=0x1E;
addrHigh=(slaveAddress>>8)&0xFE; //Calculate high/low bytes of address
addrHigh=addrHigh|0xF0;
addrLow=(slaveAddress>>1)&0xFF;
i2c_slaveAddr(addrHigh); //Set address to high byte
while (true);
} |
Slave.h:
Code: | #include <16F886.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPROTECT //No read protection
#FUSES NOWRT //No write protection
#use delay(int=8000000)
#use i2c(Slave, Slow, sda=PIN_C4, scl=PIN_C3, force_hw, address=0xa0) |
|
|