On Thu 15 Jan, Keith Howell wrote: > Subject: Re: Which Port For I2C? > > No, it really is okay to use bsf and bcf to twiddle SDA and SCL. > I do. I twiddle the bits in the TRIS registers. > AFAIK this does not disturb other bits in the register, or I/O bits. > So I2C events do not disturb other I/O bits. True, but it is _the_other_way_around_ that might be giving headaches, like having an interrupt routine twiddle some bits on the same port as you're using for I2C, right in the middle of an I2C transaction. [snip] > BTW, the last chap's I2C file looks flaky for a start. > Look at the code: Look again. > > SendI2CStart > > movlw ~(SDA_MASK|SCL_MASK) ; make sure output > > ; lines are low > > andwf I2CPORT ; when outputs are enabled > > There's nothing to guarantee the timing. > The I2C spec says the start condition is SCL falling when SDA is low. > AND the time between SDA falling and SCL falling must be > at least 4 microseconds! [snip the macros] > So that you do a START like so: > > page1 ; meaning data page > I2C_SDA_LO ; SDA goes low during SCL high > doWait3microseconds ; > I2C_SCL_LO ; Start clock train > page0 ; return with data page == 0 But you never set the state of the data register!! OK, since you are so eager to point out that my code is wrong, here is the full routine (heavily macro'd as usual). Note the two 20us delays; these are to make life easier on PIC slaves, and also go guarantee the required I2C bus timing. This code runs on 12 and 14 bit PICs. ; +---------------------------------------------------------------------+ ; | | ; | Send I2C start condition. | ; | | ; +---------------------------------------------------------------------+ ; ; In: - ; SDA and SCL floating high ; Act: Generate a slow but otherwise normal I2C start condition. ; Out: W=0 ; SDA pulled low, SCL floating high SendI2CStart movlw ~(SDA_MASK|SCL_MASK) ; make sure output lines are low andwf I2C_PORT ; when outputs are enabled if CLOCK_RATE>=600000 ldw CounterI2C,CLOCK_RATE/(3*200000) loop CounterI2C,$ ; 20us delay endif ifdef __14BIT__ bsf status_rp bcf SDA ; pull SDA low while SCL is high bcf status_rp else ifdef TrisCopy ld TrisCopy andlw ~SDA_MASK str TrisCopy else movlw SCL1_SDA0_TRIS endif tris I2C_PORT ; pull SDA low while SCL is high endif if CLOCK_RATE>=600000 ldw CounterI2C,CLOCK_RATE/(3*200000) loop CounterI2C,$ ; 20us delay endif retlw 0 ; +---------------------------------------------------------------------+ Note: LDW is MOVLW :STR LD is MOVF ,w STR is MOVWF LOOP is DECFSZ :GOTO