For the past three weeks I have been trying to solve this problem and I am at the end of my rope here. I have searched just about everywhere, on this forum and elsewhere for a solution which has gotten me this far. Hope someone can spot the error I am making.
First of all, I connect the SDA,SCL ports on both pics, and use 4k7 ohm pullups. (have tried 10k and 1k, same results).
The pics share a common ground of course.
The master is able to read data from the slave, YAY!
However, the slave is unable to receive data from the master. Can anyone here tell me why? I feel like I am so close..
My thoughts: Could it be the Internal Oscillator that is the problem? (if so, why does reading work?)
EDIT: When using Software I2C in the master, it gives the same results. So the problem must lie in the slave? It seems the slave only enters state 3 (Master Read, Last Byte Was An Adddress).
EDIT: Updated to MicroC Pro compiler, problem persists...
Cheers,
Blips
MASTER:
Code: Select all
/*
* Test configuration:
MCU: P18F4550
Dev.Board: EasyPIC4
Oscillator: INT OSC, 08.0000 MHz
*/
unsigned cnt;
unsigned float second=388;
unsigned int test=0;
unsigned int test2=0;
const address = 0xC2;
void interrupt() {
if (INTCON.TMR0IF) { // timer interrupt TMR0
cnt++; // Increment value of cnt on every interrupt
TMR0L = 96;
INTCON = 0x20; // Set T0IE, clear T0IF
if (cnt==second/2){
PORTA.F2=~PORTA.F2;
cnt=0;
}
}
}
void InitMain() {
OSCCON = 0b01111010;
TRISA = 0; LATA = 0;
TRISB = 0; LATB = 0;
TRISC = 0; LATC = 0;
TRISD = 0; LATD = 0;
TRISE = 0; LATE = 0;
ADCON0 = 0; ADCON1 = 0x0F; ADCON2 = 0; CMCON = 7;
T0CON = 0xC4; // Set TMR0 in 8bit mode, assign prescaler to TMR0
TMR0L = 96; // Timer0 initial value
INTCON = 0xA0; // Enable TMRO interrupt
cnt = 0; // Initialize cnt
//Errata
ADCON1 = 0b00001111;
TRISB = 0;
LATB = 0;
TRISB = 0b00000011;
//
Usart_Init(9600);
}
void send(unsigned short send_data, unsigned short slave){
I2C_Init(100000);
I2C_Start();
I2C_Wr(slave);
//I2C_Repeated_Start();
I2C_Wr(send_data);
I2C_Stop();
}
unsigned short read(unsigned short slave){
unsigned short read_data=0;
I2C_Init(100000);
I2C_Start();
I2C_Wr(slave+1);
read_data = I2C_Rd(0);
I2C_Stop();
return read_data;
}
void main() {
InitMain();
while(1){
// send 0xAA to slave
send(0xAA,address);
Delay_ms(1000);
//read byte from slave
test = read(address);
Usart_Write(test);
Delay_ms(1000);
}
}
Code: Select all
/*
* Test configuration:
MCU: P16F88
Dev.Board: EasyPIC4
Oscillator: INT OSC, 08.0000 MHz
Ext. Modules: -
SW: mikroC v 7.0.0.3
*/
unsigned long cnt=0;
unsigned long cnt2=0;
unsigned float second=388;
unsigned short test=0;
//------------------------------------------------------------------------------
const Addy = 0xC2; // set I2C device address
const Delay_Time = 250; // port check delay
//------------------------------------------------------------------------------
// Global Processing Variables
//------------------------------------------------------------------------------
unsigned short j=0; // just dummy for buffer read
unsigned short rxbuffer=0; //
unsigned short state=0; //
unsigned short tx_data=0; //
//------------------------------------------------------------------------------
void InitMain() {
OSCCON = 0b01110000; // INT clock used, set for 8 MHz.
ANSEL = 0;
PORTB = 0;
TRISB = 0b00000000;
TRISB = 0b00010011;
TRISB = 255;
PORTA = 0;
TRISA = 0b00000000;
OPTION_REG = 0b11000000;
INTCON = 0b11010000;
OPTION_REG = 0b11000100;
TMR0 = 96; // Timer0 initial value
INTCON = 0b11110000; // Enable TMRO interrupt
////
ADCON1 = 0x0F; // All ports set to digital
SSPADD = Addy; // Get address (7bit). Lsb is read/write flag
SSPCON = 0x36; // Set to I2C slave with 7-bit address
PIE1.SSPIF = 1; // enable SSP interrupts
PIE1.SSPIE = 1; // enable SSP interrupts
////
}
void interrupt() {
if (INTCON.F1){ // RB0/INT
INTCON.F1=0; // Clear the interrupt flag
}
if (INTCON.TMR0IF) { // timer interrupt
cnt++; // Increment value of cnt on every interrupt
cnt2++;
TMR0 = 96;
INTCON = 0x20; // Set T0IE, clear T0IF
if (cnt2==second/2){
cnt2=0;
//PORTA.F7=~PORTA.F7;
}
}
if (PIR1.SSPIF == 1){ // I2C Interrupt
if (SSPCON.SSPOV==1){
j=SSPBUF; // Read address to clear buffer
SSPCON.SSPOV=0;
}
else {
if (SSPSTAT.S==1 && SSPSTAT.R_W==0 && SSPSTAT.D_A==0 && SSPSTAT.BF==1){state=1;} // State 1: MASTER WRITE, LAST BYTE WAS AN ADDRESS
if (SSPSTAT.S==1 && SSPSTAT.R_W==0 && SSPSTAT.D_A==1 && SSPSTAT.BF==1){state=2;} // State 2: MASTER WRITE, LAST BYTE WAS DATA
if (SSPSTAT.S==1 && SSPSTAT.R_W==1 && SSPSTAT.D_A==0 && SSPSTAT.BF==0){state=3;} // State 3: MASTER READ, LAST BYTE WAS AN ADDRESS
if (SSPSTAT.S==1 && SSPSTAT.R_W==1 && SSPSTAT.D_A==1 && SSPSTAT.BF==0){state=4;} // State 4: MASTER READ, LAST BYTE WAS DATA
if (SSPSTAT.S==1 && SSPSTAT.D_A==1 && SSPSTAT.BF==0 && SSPSTAT.R_W==0 && SSPCON.CKP==1){state=5;} // State 5: MASTER NACK
switch ( state ) {
case 1:
j=SSPBUF; // Read address to clear buffer
if (SSPCON.SSPOV==1){ //overflow?
SSPCON.SSPOV=0;
j=SSPBUF; // Read address to clear buffer
}
break;
case 2:
rxbuffer=SSPBUF; // Read DATA from master.
if (SSPCON.SSPOV==1){ //overflow?
SSPCON.SSPOV=0;
rxbuffer=SSPBUF; // Read address to clear buffer
}
break;
case 3:
SSPCON.CKP =0; // Hold the SCL line low
tx_data++;
SSPBUF = tx_data; // load buffer with data to be sent to master
SSPCON.CKP =1; // Release the SCL line
j=SSPBUF; // read to empty buffer
break;
case 4:
SSPCON.CKP =0; // Hold the SCL line low
SSPBUF = tx_data; // load buffer with data to be sent to master
SSPCON.CKP =1; // Release the SCL line
j=SSPBUF; // read to empty buffer
break;
case 5:
break;
default : break;
}
j=SSPBUF; //clear buffer
}
PIR1.SSPIF = 0; // reset SSP interrupt flag
} //I2C interrupt end
}
void main() {
InitMain();
while(1)
{
}
}