News:

Let's find out together what makes a PIC Tick!

Main Menu

I2C Speed

Started by tolyan249, Feb 23, 2026, 03:50 AM

Previous topic - Next topic

tolyan249

Thank you for your help.

tolyan249



'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' I2C_Software.inc
' Software I2C writing and reading routines
' Written for the Positron8 BASIC compiler by Les Johnson
'
' Setup the default pins for SDA and SCL
'

$ifndef _I2C_SOFTWARE_INC_
$define _I2C_SOFTWARE_INC_

$ifndef I2C_SDA_Pin
    $define I2C_SDA_Pin PORTC.0
    $SendWarning "$define I2C_SDA_Pin missing from main program, so using the default pin of PORTC.4"
$endif

$ifndef I2C_SCL_Pin
    $define I2C_SCL_Pin PORTC.1
    $SendWarning "$define I2C_SCL_Pin missing from main program, so using the default pin of PORTC.3"
$endif

'----------------------------------------------------------------------------------------------
' Delay a fixed number of microseconds and clock cycles.
' These can be changed to suite the speed required by the I2C interface.
'
$define I2C_hDelayCs() DelayCS 2                        ' Delay a number of clock cycles


Proc I2C_hDelayUs()
    DelayUS 1                                           ' Delay a number of microseconds
EndProc

'----------------------------------------------------------------------------------------------
' Send a single byte to the I2C bus.
' Input     : pData holds the byte to write
' Output    : None
' Notes     : MSB first
'

Proc I2C_WriteByte(pData As Byte), Byte
    Dim bIndex As Byte
    Dim ack As Byte

    For bIndex = 7 DownTo 0
        If pData.7 = 1 Then
            PinInput I2C_SDA_Pin
        Else
            PinOutput I2C_SDA_Pin
        EndIf
        I2C_hDelayUs()
        PinInput I2C_SCL_Pin
        I2C_hDelayUs()
        PinOutput I2C_SCL_Pin
        I2C_hDelayUs()
        pData = pData << 1
    Next

    ' Perform 9th clock cycle - ACK
    PinInput I2C_SDA_Pin       ' Release the SDA line so the slave can pull it low
    I2C_hDelayUs()
    PinInput I2C_SCL_Pin       ' Raise SCL line to high level
    I2C_hDelayUs()
    ack = I2C_SDA_Pin          ' Read SDA: 0 = ACK, 1 = NACK
    PinOutput I2C_SCL_Pin      ' Pull SCL line low
    I2C_hDelayUs()

    result= ack                 ' Return ACK (0 - acknowledged, 1 - not acknowledged)
EndProc
















'----------------------------------------------------------------------------------------------
' Read a single byte from the I2C bus.
' Input     : None
' Output    : Returns the byte received
' Notes     : MSB first, sample before clock
'
Proc I2C_ReadByte(ackbit As Bit), Byte
    Dim bIndex   As Byte
    Dim wTimeOut As Word

    Result = 0
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    For bIndex = 7 DownTo 0                             ' Create a loop for the 8-bits
        Result = Result << 1
        '
        ' Wait for any clock stretching
        '
        wTimeOut = $FFFF
        Repeat                                          ' Create a loop
            PinInput I2C_SCL_Pin                        ' Make the SCL pin an Input
            Dec wTimeOut                                ' \
            If wTimeOut = 0 Then Break                  ' / Exit the loop if the timeout reaches 0
        Until I2C_SCL_Pin = 1                           ' Until the SCL pin is high
        '
        ' Read the data
        '
        I2C_hDelayUs()                                  ' Delay between pin state changes
        Result.0 = I2C_SDA_Pin
        PinOutput I2C_SCL_Pin                           ' Make the SCL pin an Output (Low)
        I2C_hDelayUs()                                  ' Delay between pin state changes
    Next


 ' --- Send ACK/NACK ---
    PinOutput I2C_SDA_Pin           ' Set SDA as output
    If ackbit = 0 Then
        I2C_SDA_Pin = 0             ' ACK - acknowledge received byte
    Else
        I2C_SDA_Pin = 1             ' NACK - decline
    EndIf

    I2C_SCL_Pin = 1                 ' Clock the ACK/NACK bit
    I2C_hDelayUs()
    I2C_SCL_Pin = 0
    I2C_hDelayUs()

    PinInput I2C_SDA_Pin            ' Release SDA pin

EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus Start condition.
' Input     : None
' Output    : None
' Notes     : A Start condition is high to low of SDA when SCL is high
'
Proc I2C_Start()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Send an I2C bus ReStart condition.
' Input     : None
' Output    : None
' Notes     : None
'
$define I2C_ReStart() I2C_Start()

'----------------------------------------------------------------------------------------------
' Send an I2C bus Stop condition.
' Input     : None
' Output    : None
' Notes     : A Stop condition is low to high of SDA when SCL is high
'
Proc I2C_Stop()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Acknowledge.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_Ack()
    I2C_hDelayUs()
    PinOutput I2C_SDA_Pin                               ' Make the SDA pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayUs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Initiate an I2C Not Acknowledge.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_NAck()
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SCL_Pin                                ' Make the SCL pin an Input (High)
    I2C_hDelayCs()                                      ' Delay a few clock cycles between pin state changes
    PinOutput I2C_SCL_Pin                               ' Make the SCL pin an Output (Low)
    DelayUS 1                                           ' Delay a clock cycle between pin state changes
    PinInput I2C_SDA_Pin                                ' Make the SDA pin an Input (High)
EndProc

'----------------------------------------------------------------------------------------------
' Setup the SDA and SCL pins for the software I2C interface.
' Input     : None
' Output    : None
' Notes     : None
'
Proc I2C_SetupPins()
    PinLow I2C_SDA_Pin                                  ' Make the I2C SDA pin an output low
    PinLow I2C_SCL_Pin                                  ' Make the I2C SCL pin an output low
EndProc

'----------------------------------------------------------------------------------------------
' Startup section
'
_I2C_Main_:
    I2C_SetupPins()                                     ' Setup the SDA and SCL pins for the software I2C interface

$endif      ' _I2C_SOFTWARE_INC_



tolyan249

I added NACK when receiving data, if the data does not need to be received, then send 1, if it needs to be received, then send 0

I2C_ReadByte(0) or I2C_ReadByte(1)