hhhsssmmm
Member level 1
Howdee people.
I have just completed an I2C interface to get two PICs talking ... MASTER and SLAVE setup.
This is working......but after successfully reading the first byte from the SLAVE and displaying on MASTER LCD ....if the MASTER again requests to read another byte from the SLAVE....then the two PICs seem to lock up...or so it seems anyway....and i do not get any more bytes received from the SLAVE.
So in short my I2C link only works for the first byte reception...after which it locks up.
Please can someone help me here to fix this problem.
my setup is...
PIC18F4423 (MASTER) and PIC18F2420 (SLAVE)
Master @ 20Mhz ceramic clock
Slave @ 8MHz internal clock
compiler used C18
Below are my test codes of MASTER and SLAVE.
thank you
hhhsssmmm
I have just completed an I2C interface to get two PICs talking ... MASTER and SLAVE setup.
This is working......but after successfully reading the first byte from the SLAVE and displaying on MASTER LCD ....if the MASTER again requests to read another byte from the SLAVE....then the two PICs seem to lock up...or so it seems anyway....and i do not get any more bytes received from the SLAVE.
So in short my I2C link only works for the first byte reception...after which it locks up.
Please can someone help me here to fix this problem.
my setup is...
PIC18F4423 (MASTER) and PIC18F2420 (SLAVE)
Master @ 20Mhz ceramic clock
Slave @ 8MHz internal clock
compiler used C18
Below are my test codes of MASTER and SLAVE.
thank you
hhhsssmmm
Code:
MASTER CODE
--------------
void main(void)
{
unsigned char ABC, DEF, HIJ; //byte holding variables
ABC = read_from_slave_PIC(0xD0); //reading from SLAVE PIC (address)
DEF = read_from_slave_PIC(0xD0); //reading from SLAVE PIC (address)
HIJ = read_from_slave_PIC(0xD0); //reading from SLAVE PIC (address)
//PRINT FIRST BYTE
SendLCD(0x80,0); //activate LCD line 1 ... col 1
//print the data byte on LCD
SendLCD(ABC,1);
Delay10KTCYx(125); //250ms delay
//PRINT SECOND BYTE
SendLCD(0x81,0); //activate LCD line 1 ... col 2
//print the data byte on LCD
SendLCD(DEF,1);
Delay10KTCYx(125); //250ms delay
//PRINT THIRD BYTE
SendLCD(0x82,0); //activate LCD line 1 ... col 3
//print the data byte on LCD
SendLCD(HIJ,1);
while(1); //loop forever
} //end of main()
unsigned char read_from_slave_PIC(unsigned char address)
{
unsigned char data_byte = 0; //variable to hold the data byte from the SLAVE
OpenI2C(); //INITIALLIZE & Configure I2C PORT
StartI2C(); //Generates a Start I2C condition
IdleI2C(); //Loops until I2C BUS is Idle
if(DataRdyI2C() == 0) //proceed if buffer is empty
{
//Send WIRTE command to SLAVE ... LSB is '0' as the WRITE bit
if(WriteI2C(address) == 0) //ACK not received from SLAVE
{
I2C_Error(); //Stop and rest I2C if link between PICs fails
while(1); //STOP program
}
IdleI2C(); //Loops until I2C BUS is Idle
}
StopI2C(); //Generates a Stop I2C condition
IdleI2C(); //Loops until I2C BUS is Idle
StartI2C(); //Generates a Start I2C condition
IdleI2C(); //Loops until I2C BUS is Idle
if(DataRdyI2C() == 0) //proceed if buffer is empty
{
//Send READ command to SLAVE ... LSB is '1' as the READ bit
if(WriteI2C(address + 1) == 0) //ACK not received from SLAVE
{
I2C_Error(); //Stop and rest I2C if link between PICs fails
while(1); //STOP program
}
IdleI2C(); //Loops until I2C BUS is Idle
}
data_byte = ReadI2C(); //read the received data from the SLAVE
NotAckI2C(); //Generates a Not Ack condition after reading data
StopI2C(); //Generates a Stop I2C condition
IdleI2C(); //Loops until I2C BUS is Idle
return data_byte; //return data byte from SLAVE
}//end of read_from_slave_PIC()
void OpenI2C(void)
{
//Reseting MSSP registers
SSPCON1 = 0x00; // power on state
SSPCON2 = 0x00; // power on state
//Selecting & Configuring I2C Master mode
SSPCON1bits.SSPM3 = 1;
SSPCON1bits.SSPM2 = 0;
SSPCON1bits.SSPM1 = 0;
SSPCON1bits.SSPM0 = 0;
SSPSTATbits.SMP = 1; //Slew rate set to NORMAL speed @ 100kHz
SSPADD = 0x63; //setting baud rate 100kHz (NORMAL)...PIC running @ 20MHz
SSPSTATbits.CKE = 0; //Disable SMBus
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
SSPCON1bits.SSPEN = 1; //Enable I2C Master port
}//end of OpenI2C()
void NotAckI2C(void)
{
SSPCON2bits.ACKDT = 1; // set acknowledge bit for NOT ACK
SSPCON2bits.ACKEN = 1; // initiate bus acknowledge sequence
}//end of NotAckI2C()
void IdleI2C(void)
{
//Test and wait until I2C module is idle
while ( (SSPCON2 & 0x1F) | (SSPSTATbits.R_W) )
continue; //keep looping until idle
}//end of IdleI2C()
unsigned char DataRdyI2C(void)
{
if(SSPSTATbits.BF == 1) // test if buffer full bit is set
return 1; // data in SSPBUF register
else
return 0; // no data in SSPBUF register
}//end of DataRdyI2C()
unsigned char ReadI2C(void)
{
SSPCON2bits.RCEN = 1; // enable master for 1 byte reception
while (SSPSTATbits.BF == 0); // wait until byte received
while(PIR1bits.SSPIF == 0); //wait for interrupt
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
return SSPBUF; // return with read byte
}//end of ReadI2C()
unsigned char WriteI2C(unsigned char data_out)
{
SSPCON2bits.ACKSTAT = 1; //reset ACK bit flag
SSPBUF = data_out; // write single byte to SSPBUF
if(SSPCON1bits.WCOL == 1) // test if write collision occurred
{
SSPCON1bits.WCOL = 0; //Reset collision bit
while(SSPSTATbits.BF == 1); // wait until write cycle is complete
}
while(PIR1bits.SSPIF == 0); //wait for interrupt
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
if(SSPCON2bits.ACKSTAT == 0) //Was there an ACK sent from DS1307?
return 1; //DS1307 sent ACK
else
return 0; //No ACK was sent
}//end of WriteI2C()
void StartI2C(void)
{
SSPCON2bits.SEN = 1; //Initiate Start condition
while(PIR1bits.SSPIF == 0); //wait for interrupt
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
}//end of StartI2C()
void StopI2C(void)
{
SSPCON2bits.PEN = 1; //Generate Stop condition
while(PIR1bits.SSPIF == 0); //wait for interrupt
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
}//end of StopI2C()
void I2C_Error(void)
{
IdleI2C(); //Loops until I2C BUS is Idle
StopI2C(); //Generates a Stop I2C condition
IdleI2C(); //Loops until I2C BUS is Idle
}//end of I2C_Error()
SLAVE CODE
------------
void main(void)
{
//Reseting MSSP registers
SSPCON1 = 0x00; // power on state
SSPCON2 = 0x00; // power on state
//I2C SLAVE mode, 7 bit address, with Start & Stop bits interrupts enabled
SSPCON1bits.SSPM3 = 1;
SSPCON1bits.SSPM2 = 1;
SSPCON1bits.SSPM1 = 1;
SSPCON1bits.SSPM0 = 0;
SSPSTATbits.SMP = 1; //Slew rate set to NORMAL speed @ 100kHz
SSPADD = 0xD0; //SLAVE address is (7bit). Lsb is R/W flag bit
SSPSTATbits.CKE = 0; //Disable SMBus
SSPCON1bits.CKP = 1; //Clock Released
SSPCON1bits.SSPEN = 1; //Enable I2C Master port
SSPCON1bits.SSPOV = 0; //Clear Buffer Overflow
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
INTCONbits.INT0IF = 0; //Reset the INT0 External Interrupt Flag bit
INTCON = 0b10010000; //Enables all high priority interrupts
//Disables all low priority peripheral interrupts
//Disable the TMR0 overflow interrupt
//Enables the INT0 external interrupt
//Disables the RB port change interrupt
d0 = SSPBUF; //clears BF
d0 = 'R'; //assign data byte to be sent to MASTER
while(1); //loop forever
} //end of main()
void HighInterrupt (void)
{
if(PIR1bits.SSPIF == 1) //if MSSP interrupt
{
if(SSPSTATbits.S == 1) // Slave receives address/data after start
{
if(SSPSTATbits.R_W == 1) // Read request from master
{
SSPBUF = d0; //load data byte for transmit
SSPCON1bits.CKP = 1; // Release SCL line to start transmit
while(SSPSTATbits.BF == 1); //stay here until BF is cleared
}
//recieve data from master
if (SSPSTATbits.D_A == 1) // Data [not address]
d3 = SSPBUF; // get data
}
if(SSPSTATbits.BF == 1) //buffer is full so empty it
d4 = SSPBUF; // read buffer to clear flag
PIR1bits.SSPIF = 0; //reset MSSP interrupt flag bit
}
}//end of HIGH ISR