Running an I2C-bus this way is out of spec and may mean that you cannot run it full speed. Some testing proved that it was possible to run the bus at 360MHz without errors. I used the Beagle I2C analyzer from TotalPhase, and it was really good for analyzing lots of I2C data to see how much errors there were in the transfers. I ended up running the bus at 100kHz, to save power and add robustness.
Since I didn't have a digital oscilloscope previously, I adopted an old Tektronix 4030 that was being scrapped at work. This must be one of the earliest generations of DSO's, the scope looks very similar to my Tek 4065. I did get it running the way I wanted it to, but it wasn't that user friendly. You had to go into a menu blip yourself to the "Normal" trigger mode, a function that usually have it's own front panel button on modern scopes...
Tektronix 4030 capture of I2C transmission. Data on top trace, clock on bottom trace. |
//I2C setup:
I2C1CON = 0x8000; //I2C module enabled
I2C1BRG = 0x13c; //= (32000000/100000 - 32000000/10000000) - 1, 100kHz SCL
//Function i2cTransmission
//Polls flag to see if there is I2C data to be sent and
//walks through the transmission process
uint16_t i2cTransmission(uint16_t i2cTransmitCycle, uint16_t *i2cstatus, uint16_t i2cData[]) {
//Polls transmit cycle flag, I2C interrupt flag and ACK-status
switch (i2cTransmitCycle) {
case 0:
if (*i2cstatus == 1) {
i2cTransmitCycle = 1;
I2C1CONbits.SEN = 1; //start condition
}
break;
case 1:
if (I2C1CONbits.SEN == 0) { //when start condition is complete, load slave address
IFS1bits.MI2C1IF = 0;
I2C1TRN = (0x60 << 1);//load DAC address
i2cTransmitCycle++;
}
break;
case 2:
//when address is ACKed:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
IFS1bits.MI2C1IF = 0;
I2C1TRN = i2cData[0]; //load first data byte
i2cTransmitCycle++;
}
break;
case 3:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
IFS1bits.MI2C1IF = 0;
I2C1TRN = i2cData[1]; //load second data byte
i2cTransmitCycle++;
}
break;
case 4:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
I2C1CONbits.PEN = 1; //stop condition
i2cTransmitCycle++;
}
break;
case 5:
if (I2C1CONbits.PEN == 0) { //when stop condition is finished, transfer is complete
i2cTransmitCycle = 0;
*i2cstatus = 0;
}
break;
default:
break;
}
return i2cTransmitCycle;
}
No comments:
Post a Comment