Hi Neil, One thing that I think is a good idea (to try to make I2C code as robust as possible) when testing master I2C code is to short the SDA and SCL line to ground (in all 3 combinations) and see if your code accounts for situations like this. In many cases you want to avoid the possibility of infinite loops in your code, and therefore you want to implement timeouts in situations where infinite loops might occur. Or you might have to use Fido the watchdog timer at a minimum. Some other ideas: 1) With the PIC MSSP module it's a good idea to check for MSSP idle state before initiating any I2C event 2) Break down the I2C events into small functions (return some sort of PASS/FAIL code -- you'll thank yourself in the future when you build higher-level I2C applications). Yes, there will be function CALL/RETURN overhead (slower than inline code), but you gain modularity and readability. 3) Don't forget about the write collision and bus collision flags I realize you are writing in assembly language, but the logic in these headerless C code snippets I wrote should give you an idea. There is no reason why they can't be ported to raw assembly language. I'm not very good (ignoramus) at posting PICLIST code without it getting mangled, so hopefully the following does not look like a tornado hit it -- I promise you it looks fine in my C source code editor. Please note that this code I wrote could *definitely* be improved (all code can be, right? :)). In the entire I2C routines I wrote, I'm not sure how well my timeout values will handle clock stretching, multi-master etc. Thanks to the MSSP module I feel it's easier to write I2C code than bit-banging (I've done both), but whether bit-banging or using the module, it's much harder to make it as *robust* as possible -- that's always the trickiest part -- the devil's always in the details. Just remember that I2C low-level routines are your "concrete" and foundation. The more time you spend and the better the foundation is, you'll have a much more solid higher-level application. Having function return codes that "bubble up" to your top layers are very useful for robust code. Anyway, have fun (the MSSP module is a blast), and hope some of these ideas will be useful. // FUNCTION: I2C_StopCondition // ----------------- // // Attempts to generates an I2C STOP condition on the bus unsigned char I2C_StopCondition(void) { // Checks for MSSP engine idle state if ( I2C_EngineIdleCheck() == FAIL ) { return FAIL; } SSPIF = 0; // Clear SSP event flag BCLIF = 0; // Clear Bus collision flag PEN = 1; // Initiate a STOP condition on SDA and SCL pins. // (automatically cleared by hardware) // If I2C event does not fire, exit with FAIL code if ( I2C_EngineInterruptConditionTimeoutCheck() == FAIL ) { return FAIL; } // Exit with FAIL code if there is a bus collision OR a stop condition was not detected last if ( ( BCLIF == 1 ) || ( STAT_P == 0 ) ) { return FAIL; } return PASS; } // FUNCTION: I2C_EngineIdleCheck // ------------------- // // Indicates whether the MSSP module is idle or not unsigned char I2C_EngineIdleCheck(void) { // Test R_W, ACKEN, RCEN, PEN, RSEN, and SEN // and exit with fail code if any of these bits are 1 (not idle) if ( ( STAT_RW == 1 ) || ( ACKEN == 1 ) || ( RCEN == 1 ) || ( PEN == 1 ) || ( RSEN == 1 ) || ( SEN == 1 ) ) { return FAIL; } else { return PASS; } } // FUNCTION: I2C_I2C_EngineInterruptConditionTimeoutCheck // -------------------------------------------- // // Once an I2C event is initiated, this routine will // indicate whether the event fired or not unsigned char I2C_EngineInterruptConditionTimeoutCheck(void) { unsigned char TimeoutCounter = 255; // Loop until I2C event fires else timeout will occur while ( SSPIF == 0 ) { if ( TimeoutCounter-- == 0 ) { return FAIL; } } return PASS; } Best regards, Ken Pergola -- http://www.piclist.com hint: The list server can filter out subtopics (like ads or off topics) for you. See http://www.piclist.com/#topics