Page 1 of 1

I2CX - software I2C master

Posted: Thu Feb 23, 2023 4:04 pm
by Jerry Messina
Many new devices no longer have an MSSP I2C peripheral (including the xv18 core devices), and the I2C peripheral in those devices is not compatible with the hdw I2C/I2C2 modules.

This new module (I2CX.bas) is a software I2C master that adds support for clock-stretching, which is useful for those slaves that require it (the existing SI2C module drives the SCL in push-pull fashion so it's not 100% I2C compliant). It has a few new features such as an event callback to let you setup IO pins (digital mode, slew rate, pullups, etc).

Here's an example... it's very similar to the existing modules

Code: Select all

program I2CX_example
device = 18F26Q71
clock = 64

include "intosc.bas"

#option I2CX_SCL = PORTC.3          // SCL
#option I2CX_SDA = PORTC.4          // SDA
#option I2CX_BAUD = 400             // 400KHz
#option I2CX_INIT_EVENT = true      // use init event for IO pin setup
include "I2CX.bas"


// setup 18FxxQ71 pins used for I2C (called by I2CX.Open/Initialize)
// most devices have weak pullups (WPU)
// _xv18 devices have addtl RxyI2C PAD controls for certain pins   
#option WPU = true
event IOinit()
    // RxyI2C PAD control present in _xv18 devices
    // [SLEW1] [SLEW0] [PU1] [PU0]   [--] [--] [TH1] [TH0]
    'const RXYI2C = (%11<<6) + (%10<<4) + %10      // slew=fast mode, pu=10x, th=SMBUS2.0
    const RXYI2C = 0    // set default to not used
    
    // set IO pin modes
  #if (I2CX_SCL = PORTC) and (I2CX_SCL@ = 3)    // check for PORTC.3
    ANSELC.bits(3) = 0      // 0=digital, 1=analog mode
    SLRCONC.bits(3) = 0     // 0=max rate, 1=limited slewrate (RxyI2C SLEW=00)
    INLVLC.bits(3) = 0      // 0=TTL, 1=ST (RxyI2C TH=00)
   #if (WPU)
    WPUC.bits(3) = 1        // enable weak pullup (if supported and RxyI2C PU=00)
   #endif
    RC3I2C = RXYI2C
  #endif

  #if (I2CX_SDA = PORTC) and (I2CX_SDA@ = 4)    // check for PORTC.4
    ANSELC.bits(4) = 0      // 0=digital, 1=analog mode
    SLRCONC.bits(4) = 0     // 0=max rate, 1=limited slewrate (RxyI2C SLEW=00)
    INLVLC.bits(4) = 0      // 0=TTL, 1=ST (RxyI2C TH=00)
   #if (WPU)
    WPUC.bits(4) = 1        // enable weak pullup (if supported and RxyI2C PU=00)
   #endif
    RC4I2C = RXYI2C
  #endif
end event

dim st as boolean
dim b as byte

// initialize I2C using the IOinit event to setup pins
I2CX.open(IOinit)       // requires 'I2CX_INIT_EVENT = true'

// check if bus ok
st = I2CX.CheckBus()

// see if slave device addr $02 responds (ACK/NACK)
st = I2CX.IsPresent($02)

// write $55 to addr $02
I2CX.Start()
I2CX.WriteByte($02)
I2CX.WriteByte($55)
I2CX.Stop()

// read two bytes from addr $02
I2CX.Start()
I2CX.WriteByte($02)
I2CX.Restart()
b = I2CX.ReadByte(I2C_ACK)
b = I2CX.ReadByte(I2C_NACK)
I2CX.Stop()

I2CX.Close()

end program
I2CX will be included in the next update.