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 processuint16_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