SI2C Query

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Post Reply
User avatar
Steven
BETA Tester
Posts: 406
Joined: Tue Oct 03, 2006 8:32 pm
Location: Cumbria, UK

SI2C Query

Post by Steven » Mon Nov 05, 2007 9:48 pm

On the topic of software I2C again...! Currently, the SI2C library pulls the clock low and high, acting as a master. However, should it instead:
(i) pull the clock (SCL) low, as required, by setting the SCL pin as an output and bringing this low (as it does currently), then...
(ii) when the clock should go high, set the SCL pin as an input and allow the pull-up resistors on the bus to pull it high?
Is there a danger of setting the clock high by using a high output pin that this might be sinked directly into another device/PIC on the I2C bus that is holding the clock low, e.g. for clock stretching?

Any thoughts from anyone welcome.

Thanks,

Steve

johngb
Registered User
Registered User
Posts: 139
Joined: Tue Oct 03, 2006 10:16 pm

Post by johngb » Mon Nov 05, 2007 10:33 pm

I think I agree with you - that is certainly the way the MSSP module handles the interface. It only ever asserts low not high, relying on pull up resistors to allow the lines to go high.
JohnB

User avatar
Steven
BETA Tester
Posts: 406
Joined: Tue Oct 03, 2006 8:32 pm
Location: Cumbria, UK

Post by Steven » Mon Nov 05, 2007 11:23 pm

OK, thanks John. I'll alter my copy of the library and see if it still works OK with my I2C digital compass.

User avatar
Steven
BETA Tester
Posts: 406
Joined: Tue Oct 03, 2006 8:32 pm
Location: Cumbria, UK

Post by Steven » Tue Nov 06, 2007 6:15 pm

I've now made the changes to the SI2C module and it still works OK. Is this a valid alteration?

Steve

Code: Select all

(*
*****************************************************************************
*  Name    : SI2C Library                                                   *
*  Author  : David John Barker                                              *
*  Notice  : Copyright (c) 2003 Mecanique                                   *
*          : All Rights Reserved                                            *
*  Date    : 25/07/05                                                       *
*  Version : 1.1                                                            *
*  Notes   : 1.1 Corrected 'NotAcknowledged' in WriteByte()                 *
*          :     Added WaitForWrite() routine                               *
*          : 1.0 Initial release                                            *
*****************************************************************************
*)
Module SI2C

Include "system.bas"

// SCL option...
#if IsOption(I2C_SCL) And Not IsValidPortPin(I2C_SCL) 
   #error I2C_SCL, "Invalid option. I2C clock must be a valid port pin."
#endif
#option I2C_SCL = PORTC.3

// SDA option...
#if IsOption(I2C_SDA) And Not IsValidPortPin(I2C_SDA) 
   #error I2C_SDA, "Invalid option. I2C data line must be a valid port pin."
#endif
#option I2C_SDA = PORTC.4

// configure SCL and SDA...
Dim
   SCL As I2C_SCL.I2C_SCL@,
   SDA As I2C_SDA.I2C_SDA@
   
// SI2C constants...
Public Const 
   I2C_ACKNOWLEDGE = 0,       // acknowledge data bit (acknowledge)
   I2C_NOT_ACKNOWLEDGE = 1    // acknowledge data bit (NOT acknowledge)

Public Dim
   NotAcknowledged As Boolean

{
****************************************************************************
* Name    : SDAHigh (PRIVATE)                                              *
* Purpose : Allows SDA to pull high by I2C bus pull-up resistors           *
****************************************************************************
}
Inline Sub SDAHigh()
   Input(SDA)
End Sub
{
****************************************************************************
* Name    : SCLHigh (PRIVATE)                                              *
* Purpose : Allows SCL to pull high by I2C bus pull-up resistors           *
****************************************************************************
}
Inline Sub SCLHigh()
   Input(SCL)
End Sub
{
****************************************************************************
* Name    : SDALow (PRIVATE)                                               *
* Purpose : Sets SDA to output and force to low as SDA already set low     *
****************************************************************************
}
Inline Sub SDALow()
   Output(SDA)
End Sub
{
****************************************************************************
* Name    : SCLLow (PRIVATE)                                               *
* Purpose : Sets SCL to output and force to low as SCL already set low     *
****************************************************************************
}
Inline Sub SCLLow()
   Output(SCL)
End Sub
{
****************************************************************************
* Name    : Delay (PRIVATE)                                                *
* Purpose : Delay a fixed number of microseconds                           *
****************************************************************************
}
Inline Sub Delay()
   DelayUS(5)
End Sub
{
****************************************************************************
* Name    : ToggleClock (PRIVATE)                                          *
* Purpose : Clock the I2C bus                                              *
****************************************************************************
}
Inline Sub ToggleClock()
   SCLHigh()
   Delay
   SCLLow()
   Delay
End Sub
{
****************************************************************************
* Name    : ShiftOut (PRIVATE)                                             *
* Purpose : Shift out a byte value, MSB first                              *
****************************************************************************
}
Sub ShiftOut(pData As Byte)
   Dim Index As Byte
   Index = 8
   Repeat
      If pData.7 = 1 Then
         SDAHigh()
      Else
         SDALow()
      EndIf
      ToggleClock
      pData = pData << 1
      Dec(Index)
   Until Index = 0
   ClrWDT
End Sub
{
****************************************************************************
* Name    : ShiftIn (PRIVATE)                                              *
* Purpose : Shift in a byte value, MSB first, sample whilst clock high     *
****************************************************************************
}
Function ShiftIn() As Byte
   Dim Index As Byte
   Dim TimeOut As Byte
   Index = 8
   Result = 0
   Input(SDA)
   Repeat
      SCLHigh()
      TimeOut = $FF
      Repeat
         Dec(TimeOut)
         Delay
      Until (SCL = 1 Or TimeOut = 0) // wait for any clock stretching by slave
      Result = Result << 1
      Result.0 = SDA
      SCLLow()
      Delay
      Dec(Index)
   Until Index = 0
   ClrWDT
End Function
{
****************************************************************************
* Name    : Initialize                                                     *
* Purpose : Initialize I2C bus                                             *
****************************************************************************
}         
Public Sub Initialize()
   SCLHigh()
   SDAHigh()
   Low(SCL)     // Set low so that pulls low when set to output
   Low(SDA)     // Set low so that pulls low when set to output
End Sub
{
****************************************************************************
* Name    : Start                                                          *
* Purpose : Send an I2C bus start condition. A start condition is HIGH to  *
*         : LOW of SDA line when the clock is HIGH                         *
****************************************************************************
}         
Public Sub Start()
  SDAHigh()
  Delay
  SCLHigh()
  Delay
  SDALow()
  Delay
  SCLLow()
  Delay
End Sub
{
****************************************************************************
* Name    : Stop                                                           *
* Purpose : Send an I2C bus stop condition. A stop condition is LOW to     *
*         : HIGH of SDA when line when the clock is HIGH                   *
****************************************************************************
}         
Public Sub Stop()
  SDALow()
  Delay
  SCLHigh()
  Delay
  SDAHigh()
  Delay
End Sub
{
****************************************************************************
* Name    : Restart                                                        *
* Purpose : Send an I2C bus restart condition                              *
****************************************************************************
}         
Public Sub Restart()
   Start
End Sub
{
****************************************************************************
* Name    : Acknowledge                                                    *
* Purpose : Initiate I2C acknowledge                                       *
*         : pAck = 1, NOT acknowledge                                      *
*         : pAck = 0, acknowledge                                          *
****************************************************************************
}         
Public Sub Acknowledge(pAck As Bit = I2C_ACKNOWLEDGE)
   If pAck = 1 Then
      SDAHigh()
   Else
      SDALow()
   EndIf
   ToggleClock 
End Sub
{
****************************************************************************
* Name    : ReadByte (OVERLOAD)                                            *
* Purpose : Read a single byte from the I2C bus                            *
****************************************************************************
}         
Public Function ReadByte() As Byte
   Result = ShiftIn
End Function
{
****************************************************************************
* Name    : ReadByte (OVERLOAD)                                            *
* Purpose : Read a single byte from the I2C bus, with Acknowledge          *
****************************************************************************
}         
Public Function ReadByte(pAck As Bit) As Byte
  Result = ShiftIn
  Acknowledge(pAck)
End Function
{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a single byte to the I2C bus                             *
****************************************************************************
}         
Public Sub WriteByte(pData As Byte)
   ShiftOut(pData) 

   // look for ack...
   Input(SDA)
   SCLHigh()
   Delay
   NotAcknowledged = Boolean(SDA)
   SCLLow()
   SDALow()
End Sub
{
****************************************************************************
* Name    : WaitForWrite                                                   *
* Purpose : Wait until write sequence has completed                        *
****************************************************************************
}         
Public Sub WaitForWrite(pControl As Byte)
   Dim Timeout As Byte
   Timeout = $FF
          
   Start
   WriteByte(pControl)  
   While NotAcknowledged And (Timeout > 0)
      Restart
      WriteByte(pControl)  
      Dec(Timeout)
   Wend
   Stop
End Sub

User avatar
ohararp
Posts: 194
Joined: Tue Oct 03, 2006 11:29 pm
Location: Dayton, OH USA
Contact:

Post by ohararp » Thu Jan 22, 2009 8:55 pm

Steven,

Thanks for the code on this. I have been trying to talk to a DS1340C and was having a bit of trouble until you posted this new code. I dropped it in and it worked a treat!
Thanks Ryan
$25 SMT Stencils!!!
www.ohararp.com/Stencils.html

User avatar
Steven
BETA Tester
Posts: 406
Joined: Tue Oct 03, 2006 8:32 pm
Location: Cumbria, UK

Post by Steven » Thu Jan 22, 2009 9:45 pm

Good to know it's been of use - thanks for letting me know.

Jon Chandler
Registered User
Registered User
Posts: 185
Joined: Mon Mar 10, 2008 8:20 am
Location: Seattle, WA USA
Contact:

Post by Jon Chandler » Wed Jan 28, 2009 2:46 am

Steven,

This upgrade did the trick for me too in trying to determine some intermittent communications with a TI I2C chip. Thanks for the great support.


Jon

Post Reply