Hi all,
Here is an unusual one, maybe someone brighter than me can help.
I have a pic18f4550 as a USB device and a master to a pic16f88 acting as a slave that will be doing analogue sampling. At the moment, all the master is doing is repeating a write of one bight. After many hours not having luck trying to debug both, I hooked the master up to an eeprom just to get that one sorted from an I2C standpoint. No problems, too easy.
I did find that I hadn't set my baud rate correctly, it was at about 225kHz but now fixed that and its at 100kHz (verified with scope) and pins tied high with 2k2 resistors.
After i fixed that, the slave worked - kind of.
I have the master turning on a green light when an ack is received and a red light when a nack is received (easier to see than getting the scope triggering properly). With the master running by itself and the slave in debug with an ICD2 through MPLAB, I couldn't get any acks when running the program right after a chip burn. However, after a reset, I could, but then only acks for a second maybe (and some times more, sometime less).
So after some more hours of debugging I thought I had it. It was acking continuously. So I thought I'd clean up my code and get rid of all the temporary variables that I was using to find faults.
This is where it got strange. After I deleted one temporary variable in the isr (which did a second bitmask on the SSPSTATUS register, checking for a stop bit ) I could only get an ack for a second again. In the code below you'll see in the interrupt routine that there are 4 NOP instructions. One more than that, < 1 second of acking, one less than that, < 1 second of acking, 4 - continuous acking.
Anyone with ideas? Why is 4 nop's the magic number?
By the way, using Hi-Tech for the slave and C18 for the master.
Slave code:
Here is part of the master code, there is a load of USB code that i didn't include as part of this. This function gets called by a flag in the main function, set on a timer interrupt.
In main() is:
the function on the master is:
I have spent hours looking over forums and there are others with similar problems but nothing has seemed to work, maybe if someone could offer a solution to this it may also help others starting out in I2C between two PICs.
Thanks for reading,
Dan.
Here is an unusual one, maybe someone brighter than me can help.
I have a pic18f4550 as a USB device and a master to a pic16f88 acting as a slave that will be doing analogue sampling. At the moment, all the master is doing is repeating a write of one bight. After many hours not having luck trying to debug both, I hooked the master up to an eeprom just to get that one sorted from an I2C standpoint. No problems, too easy.
I did find that I hadn't set my baud rate correctly, it was at about 225kHz but now fixed that and its at 100kHz (verified with scope) and pins tied high with 2k2 resistors.
After i fixed that, the slave worked - kind of.
I have the master turning on a green light when an ack is received and a red light when a nack is received (easier to see than getting the scope triggering properly). With the master running by itself and the slave in debug with an ICD2 through MPLAB, I couldn't get any acks when running the program right after a chip burn. However, after a reset, I could, but then only acks for a second maybe (and some times more, sometime less).
So after some more hours of debugging I thought I had it. It was acking continuously. So I thought I'd clean up my code and get rid of all the temporary variables that I was using to find faults.
This is where it got strange. After I deleted one temporary variable in the isr (which did a second bitmask on the SSPSTATUS register, checking for a stop bit ) I could only get an ack for a second again. In the code below you'll see in the interrupt routine that there are 4 NOP instructions. One more than that, < 1 second of acking, one less than that, < 1 second of acking, 4 - continuous acking.
Anyone with ideas? Why is 4 nop's the magic number?
By the way, using Hi-Tech for the slave and C18 for the master.
Slave code:
Rich (BB code):
#include <htc.h>
#define true 1
#define BYTES 64
/***** Global Variable ********/
void delay(int);
void init(void);
void i2c_init(void);
void i2c_start(void);
void i2c_write(char);
void i2c_stop(void);
void i2c_wait(void);
void i2c_init(void)
{
SSPEN = 1; //Enables Serial Port Mode
INTCONbits.PEIE = 1;
SSPCONbits.CKP =1; //Clock Released
SSPBUF = 0 ;
/* SSPCON REGISTERS */
SSPCONbits.SSPM = 0x6;
/* SSPSTAT REGISTERS */
TRISB4 = 1; // SCL as input
SMP = 0; //Slew Rate Control Disabled
CKE = 0; //SMBus Specific Inputs Disabled
SSPADD = 0xAE;
}
void delay(int pause)
{
unsigned int i, j, k;
unsigned int clock = 6;
unsigned int cycle = 14;
for(i = 0; i <= pause; i++){
for(j = 0; j <= clock; j++){
for(k = 0; k <= cycle; k++){
asm("nop");
}}}
}
void Initialise()
{
SSPSTAT = 0;
ANSEL = 0b1111; // Select Channel 0 through to 3 as analogue inputs
TRISA0 = 1; // RA0 as input
TRISA1 = 1; // RA1 as input
TRISA2 = 1; // RA2 as input
TRISA3 = 1; // RA3 as input
TRISB1 = 1; // SDA as input
ADCON0 = 0b11000001;
ADCON1 = 0b10000000;
INTCONbits.PEIE = 1;
PIE1bits.SSPIE = 1;
GIE = 1;
TMR0IF=0;
T0CS=0;
TMR0IE=0;
TMR0 = 0x00;
OPTION_REG = 0b11001000;
}
void main(void)
{
Initialise();
i2c_init();
while (true)
{
i2c_wait();
}
}
void i2c_write(char byte)
{
SSPBUF = byte;
i2c_wait();
}
void i2c_wait(void)
{
while ( SSPIF==0 );
SSPIF = 0;
}
void interrupt isr(void)
{
unsigned char CASE_SWITCH;
unsigned char temp;
unsigned char dataToMaster;
if (PIR1bits.SSPIF == 1)
{
PIR1bits.SSPIF = 0; // reset SSP interrupt flag
CASE_SWITCH = SSPSTAT & 0x2D;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
switch(CASE_SWITCH)
{
case 0x09 : // master write last byte was addr
{
if(SSPCONbits.SSPOV == 0)
{
SSPCONbits.CKP = 0;
temp = SSPBUF; // just dummy value to clear
SSPCONbits.CKP = 1;
break;
}
}
case 0x29: // master write last byte was data
{
if(SSPCONbits.SSPOV == 0)
{
SSPCONbits.CKP = 0;
readValue = SSPBUF; // just dummy value to clear
SSPCONbits.CKP = 1;
break;
}
}
case 0x0c: // master read last byte was addr
{
temp = SSPBUF; // just dummy value to clear
SSPCONbits.CKP = 0;
SSPBUF = dataToMaster;
SSPCONbits.CKP = 1;
break;
}
case 0x2c: // master read last byte was data
{
temp = SSPBUF; // just dummy value to clear
SSPCONbits.CKP = 0;
SSPBUF = dataToMaster;
SSPCONbits.CKP = 1;
break;
}
case 0x28: // S = 1, R_W = 0, D_A = 1, BF = 0
{
temp = SSPBUF; // just dummy value to clear
// Master NACK
break;
}
default:
break;
}
}
}
In main() is:
Rich (BB code):
writeByteI2C(rw, 0xAE, 0x78 );
Rich (BB code):
unsigned char writeByteI2C( unsigned char rw, unsigned char add, unsigned char data )
{
unsigned char result = -1;
if (rw == 0)
{
add = 0xFE & add;
}
else
{
add = 0x01 | add;
}
IdleI2C(); // ensure module is idle
StartI2C(); // initiate START condition
while ( SSPCON2bits.SEN ); // wait until start condition is over
//WriteI2C( ControlByte ); // write 1 byte - R/W bit should be 0
IdleI2C(); // ensure module is idle
result = WriteI2C( add ); // write address
IdleI2C(); // ensure module is idle
if (result == 0)
{
PORTAbits.RA4 = 1;
PORTAbits.RA5 = 0;
result = WriteI2C ( data ); // Write data byte
if (result == 0)
{
PORTAbits.RA4 = 1;
PORTAbits.RA5 = 0;
}
else
{
PORTAbits.RA4 = 0;
PORTAbits.RA5 = 1;
}
}
else
{
PORTAbits.RA4 = 0;
PORTAbits.RA5 = 1;
}
IdleI2C(); // ensure module is idle
StopI2C(); // send STOP condition
while ( SSPCON2bits.PEN ); // wait until stop condition is over
return ( 0 ); // return with no error
}
Thanks for reading,
Dan.
Last edited: