Hi all - is it possible to have 2 I2C busses in Proton?
I have some routines that enable 2 x i2c channels.
I will dig out the code a bit later
Tim
This is the i2c routine
$ifndef _Software_I2C_Fixed_Pins_inc_
$define _Software_I2C_Fixed_Pins_inc_
'
' /\\\\\\\\\
' /\\\///////\\\
' \/\\\ \/\\\ /\\\ /\\\
' \/\\\\\\\\\\\/ /\\\\\ /\\\\\\\\\\ /\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\
' \/\\\//////\\\ /\\\///\\\ \/\\\////// /\\\/////\\\ \////\\\//// \////\\\//// \////////\\\
' \/\\\ \//\\\ /\\\ \//\\\ \/\\\\\\\\\\ /\\\\\\\\\\\ \/\\\ \/\\\ /\\\\\\\\\\
' \/\\\ \//\\\ \//\\\ /\\\ \////////\\\ \//\\/////// \/\\\ /\\ \/\\\ /\\ /\\\/////\\\
' \/\\\ \//\\\ \///\\\\\/ /\\\\\\\\\\ \//\\\\\\\\\\ \//\\\\\ \//\\\\\ \//\\\\\\\\/\\
' \/// \/// \///// \////////// \////////// \///// \///// \////////\//
' Let's find out together what makes a PIC Tick!
'
' Software I2C writing and reading routines using fixed pins for the SDA and SCL lines.
'
' Written for the Positron8 and Positron16 BASIC compilers by Les Johnson
'
' Set the pins used for the I2C SDA and SCL lines
'
' Symbol I2C_SDA_Pin = PORTC.3 ' Holds the pin used for the SDA line
' Symbol I2C_SCL_Pin = PORTC.4 ' Holds the pin used for the SCL line
'
' Create some global variables for the routines
'
Dim I2C_bBitIndex As Byte Access ' Holds the index for the bits to send/receive on the I2C line
Dim I2C_bData As Byte Access ' Holds the byte sent or received
Dim bTimeout As Byte Access
'----------------------------------------------------------------------------------------------
' Create a very small delay to slow down the I2C interface (if required)
' Input : None
' Output : None
' Notes : None
'
$define I2C_hDelayL() Delayus 2
$define I2C_hDelayH() Delayus 3
'----------------------------------------------------------------------------------------------
' Write a byte to the I2C bus
' Input : pData holds the byte to write
' Output : None
' Notes : MSB first
'
Proc I2C_WriteByte(pData As I2C_bData)
For I2C_bBitIndex = 7 DownTo 0 ' Create a loop for the 8-bits to write
If pData.7 = 1 Then ' Is bit-7 of pData set?
PinInput I2C_SDA_Pin ' Yes. So make the SDA pin an input (made high by the pull-up resistor)
Else ' Otherwise...
PinLow I2C_SDA_Pin ' Make the SDA pin an output low
EndIf '
I2C_hDelayLL() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL() ' Create a small delay
Rol pData ' Rotate pData left by 1 bit
Next
'
' Close up the interface
'
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
bTimeout = $FF ' \
Repeat ' / Create a loop for the clock stretching
If I2C_SCL_Pin = 1 Then Break ' Exit the loop when the SCL pin is high
Dec bTimeout ' \ Until the timeout value reaches 0
Until bTimeout = 0 ' /
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL() ' Create a small delay
EndProc
'----------------------------------------------------------------------------------------------
' Read a byte from the I2C bus
' Input : None
' Output : Returns the byte received
' Notes : MSB first
'
Proc I2C_ReadByte(), I2C_bData
Result = 0 ' Clear the result of the procedure before entering the loop
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
For I2C_bBitIndex = 7 DownTo 0 ' Create a loop for the 8-bits to read
Result = Result << 1 ' Shift the result value left by 1 bit
'
' Wait for any clock stretching required, with a small timeout
'
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
bTimeout = $FF ' \
Repeat ' / Create a loop for the clock stretching
If I2C_SCL_Pin = 1 Then Break ' Exit the loop when the SCL pin is high
Dec bTimeout ' \ Until the timeout value reaches 0
Until BTimeout = 0 ' /
'
' Read the data
'
I2C_hDelayL() ' Create a small delay
Result.0 = I2C_SDA_Pin ' Read the state of the SDA pin into bit-0 of the result
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL() ' Create a small delay
Next
EndProc
'----------------------------------------------------------------------------------------------
' Send an I2C bus Start condition
' Input : None
' Output : None
' Notes : None
'
Proc I2C_Start()
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SDA_Pin ' Make the SDA pin an output low
I2C_hDelayL() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL()
EndProc
'----------------------------------------------------------------------------------------------
' Send an I2C bus ReStart condition
' Input : None
' Output : None
' Notes : None
'
Proc I2C_ReStart()
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SDA_Pin ' Make the SDA pin an output low
I2C_hDelayL() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL()
EndProc
'----------------------------------------------------------------------------------------------
' Send an I2C bus Stop condition
' Input : None
' Output : None
' Notes : None
'
Proc I2C_Stop()
PinLow I2C_SDA_Pin ' Make the SDA pin an output low
I2C_hDelayL() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
I2C_hDelayH()
EndProc
'----------------------------------------------------------------------------------------------
' Initiate an I2C Acknowledge
' Input : None
' Output : None
' Notes : None
'
Proc I2C_Ack()
I2C_hDelayL()
PinLow I2C_SDA_Pin ' Make the SDA pin an output low
I2C_hDelayL() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL() ' Create a small delay
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
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 (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinInput I2C_SCL_Pin ' Make the SCL pin an input (made high by the pull-up resistor)
I2C_hDelayH() ' Create a small delay
PinLow I2C_SCL_Pin ' Make the SCL pin an output low
I2C_hDelayL() ' Create a small delay
PinInput I2C_SDA_Pin ' Make the SDA pin an input (made high by the pull-up resistor)
EndProc
$endif ' _Software_I2C_Fixed_Pins_inc_
And this is it in use on 2 channels
Sorry it's not really obvious but I'm just cut/pasting my code
'*******************************************************************************
'* Title : ReadPressures
'* Input : None
'* Notes : Reads both pressure sensors and places the result in a ring buffer
'*******************************************************************************
Proc ReadPressures()
Dim wTemp1 As Word
xP1Error = cFalse
xP2Error = cFalse
EnablePressurei2c1()
If bPressureBufferIndex >= cPressureBufferSize Then ' Check the pointer is in bounds
bPressureBufferIndex = 0
EndIf
' Read Pressure sensor 1
I2C_Start()
I2C_WriteByte(cPSensorI2CAddress)
delayus 2
wTemp1.Byte1 = I2C_ReadByte()
I2C_Ack()
wTemp1.Byte0 = I2C_ReadByte()
I2C_NAck()
I2C_Stop()
' Test result to see if there was any responce and flag an error if so
if wTemp1 = $FFFF then
xP1Error = cTrue
wTemp1 = 0
Endif
Wtemp1.15 = 0 ' There are error flags that have to be masked
Wtemp1.14 = 0
awPressureBuffer1[bPressureBufferIndex] = wTemp1 ' Save to the ring buffer
DisablePressurei2c1()
EnablePressurei2c2() ' Swap over to the other pressure sensor
' Read Pressure sensor 2
I2C_Start()
I2C_WriteByte(cPSensorI2CAddress)
delayus 2
wTemp1.Byte1 = I2C_ReadByte()
I2C_Ack()
wTemp1.Byte0 = I2C_ReadByte()
I2C_NAck()
I2C_Stop()
' Test result to see if there was any responce and flag an error if so
if wTemp1 = $FFFF then
xP2Error = cTrue
wTemp1 = 0
Endif
Wtemp1.15 = 0 ' There are error flags that have to be masked
Wtemp1.14 = 0
awPressureBuffer2[bPressureBufferIndex] = wTemp1 ' Save to the ring buffer
DisablePressurei2c2()
Inc bPressureBufferIndex ' Move to the next place in the ring buffer
EndProc
Looking at my code and remembering what I did its come back to me that the way I handled it in this code was to have hardware buffers on the i2c lines and enabled and disabled them to get the 2 i2c ports
I do have a 2 channel code I will dig it out
It was written as you see by Les
If it can be a software variant then why not use I2CIn and I2Cout?
I have I²C components on various ports and that works fine with these Positron commands.
Quote from: Peter Truman on Jan 02, 2025, 02:44 AMHi all - is it possible to have 2 I2C busses in Proton?
Hi Peter, are you talking about Hardware or Software I2C? Both are possible.
Thanks everyone - I2Cin and I2C out look like the simplest way of doing this - It looks like the software implementation is the easiest (I need simple - bit thick!) - I haven't designed the hardware yet so I'm not clear what I need, just as long as I know it's possible, I guess I can use any standard I/O pin for either hardware or software? - the application doesn't need to run a lightening speed or anything.
You guys rock and I very much appreciate the support from the forum generally!