'------------------------------------------------------------------
' I2C Library for PIC18F26K22 using the MSSP1 module
' Author: COS, 2025/07/20, 2025/07, 2024/10, Pic18 Oshonsoft v5.88
' dogflu66@yahoo.es
' Description:
' This library provides functions for controlling devices on an I2C
' bus in master mode using the MSSP1 module. It includes functions
' for initializing the bus, reading and writing data, and handling
' the START, STOP, and RESTART control signals.
' This implementation is for the PIC18F26K22 microcontroller.
' It is recommended to use this library for managing communications
' with I2C slave devices, such as EEPROMs, sensors, or RTCs.
'-------------------------------------------------------------------
' I2C Pin
Symbol I2C_IO_SCL = TRISC.3
Symbol I2C_IO_SDA = TRISC.4
'------------------------------------------------------------------
Const ACK = 0 'ACK is required
Const NACK = 1 'NACK is required
Const DELAY_END_WRITE = 25 ' Delay in microseconds after writing
'-------------------------------------------------------------------
' Function:    Init_I2C
' Description:
' Initializes the MSSP1 module in I2C master mode and configures the
' communication speed according to the provided parameters.
' Arguments:
' - i2c_Khz (Long): I2C clock frequency in kHz.
' - clock_Mhz (Long): System clock frequency in MHz.
' Returns:
'-------------------------------------------------------------------
Function Init_I2C(i2c_Khz As Long, clock_Mhz As Long) As Byte
    SSPSTAT = 0x80 ' Disable overflow detection for high-speed
    SSPCON1 = 0x28 ' Configure MSSP1 module in I2C master mode
    SSPCON2 = 0x00 ' Reset additional control
    SSPADD = ((clock_Mhz * 1000000) / (4 * (i2c_Khz * 1000))) - 1 ' Calculate SSP1ADD
    High I2C_IO_SCL ' Set SCL as input
    High I2C_IO_SDA ' Set SDA as input
    WaitMs 1 ' Brief wait for stabilization
End Function
'-------------------------------------------------------------------
' Function:    START_I2C
' Description:
' Sends a START condition on the I2C bus to begin a transaction
' with a slave device.
' Arguments: None.
' Returns:
'-------------------------------------------------------------------
Function START_I2C() As Byte
   'While SSPCON2.SEN = 1 ' Wait if a transaction is already starting
   'Wend
    SSPCON2.SEN = 1 ' Initiate START condition
    While SSPCON2.SEN = 1 ' Wait for completion
    Wend
End Function
'-------------------------------------------------------------------
' Function:    STOP_I2C
' Description:
' Sends a STOP condition on the I2C bus, ending a transaction
' with a slave device.
' Arguments: None.
' Returns:
'-------------------------------------------------------------------
Function STOP_I2C() As Byte
    'While SSPCON2.PEN = 1 ' Wait if a transaction is already stopping
    'Wend
    SSPCON2.PEN = 1 ' Initiate STOP condition
    While SSPCON2.PEN = 1 ' Wait for completion
    Wend
End Function
'-------------------------------------------------------------------
' Function:    ReStart_I2C
' Description:
' Generates a RESTART condition on the I2C bus, allowing the
' continuation of a transaction without stopping it.
' Arguments: None.
' Returns:
'-------------------------------------------------------------------
Function ReStart_I2C() As Byte
    SSPCON2.RSEN = 1 ' Initiate RESTART condition
    While SSPCON2.RSEN = 1 ' Wait for completion
    Wend
End Function
'-------------------------------------------------------------------
' Function:    WRITE_I2C
' Description:
' Sends a byte of data over the I2C bus to the slave device.
' Arguments:
' - data (Byte): The data byte to send.
' Returns:
' - 0 if the slave acknowledges the write (ACK received).
' - 1 if no ACK is received from the slave (error).
'-------------------------------------------------------------------
Function WRITE_I2C(data As Byte) As Byte
    Symbol _RETURN = WRITE_I2C
    _RETURN = 0
	PIR1.SSPIF = 0
    SSPBUF = data ' Load the byte into the buffer
    While SSPSTAT.BF = 1 ' Wait for transmission to complete
    Wend
	' Wait until the ACK status is read.
    While PIR1.SSPIF = 0
    Wend
    _RETURN.0 = SSPCON2.ACKSTAT ' Return ACK status (0 if success)
    WaitUs DELAY_END_WRITE ' Delay after writing
End Function
'-------------------------------------------------------------------
' Function:    READ_I2C
' Description:
' Reads a byte from the I2C bus from the slave device and sends an
' ACK or NACK depending on the provided parameter.
' Arguments:
' - _ack (Byte): 0 to send ACK, 1 to send NACK after reading.
' Returns:
' - The byte read from the slave device.
'-------------------------------------------------------------------
Function READ_I2C(_ack As Byte) As Byte
    SSP1CON2.RCEN = 1 ' Enable reception
    While SSPSTAT.BF = 0 ' Wait for the byte to be received
    Wend
    ReturnValue SSP1BUF ' Return the received byte
    If _ack = 0 Then
        SSPCON2.ACKDT = 1 ' Prepare NACK
    Else
        SSPCON2.ACKDT = 0 ' Prepare ACK
    Endif
    SSPCON2.ACKEN = 1 ' Send ACK/NACK signal
    While SSPCON2.ACKEN = 1 ' Wait for completion
    Wend
End Function
'-------------------------------------------------------------------
' Function:    WriteDevice_I2C
' Description:
' Initiates a write transaction with an I2C slave device.
' Sends the slave address and then a data byte.
' Arguments:
' - address (Byte): Slave device address.
' - data (Byte): Data to write to the slave.
' Returns:
' - 0 if the operation was successful.
' - 1 if an error occurred (missing ACK).
'-------------------------------------------------------------------
Function WriteDevice_I2C(ByVal address As Byte, ByVal data As Byte) As Byte
    START_I2C() ' Start condition
    'If WRITE_I2C(address << 1) = 1 Then ' Send slave address + write bit
    '    Call STOP_I2C() ' Error, stop transaction
     '   ReturnValue 1 ' Error
    'Else
		WRITE_I2C(address)
        WRITE_I2C(data) ' Send data
        Call STOP_I2C() ' End transaction
        ReturnValue 0 ' Success
    'Endif
End Function
'-------------------------------------------------------------------
' Function:    ReadDevice_I2C
' Description:
' Initiates a read transaction with an I2C slave device.
' Sends the slave address and reads a data byte.
' Arguments:
' - address (Byte): Slave device address.
' Returns:
' - The byte read from the slave device.
' - 0 if an error occurred (missing ACK).
'-------------------------------------------------------------------
Function ReadDevice_I2C(ByVal address As Byte) As Byte
	Symbol _RETURN = ReadDevice_I2C
    START_I2C() ' Start condition
    If WRITE_I2C((address << 1) + 1) = 1 Then ' Send slave address + read bit
        STOP_I2C() ' Error, stop transaction
        _RETURN = 0 ' Error
    Else
        _RETURN = READ_I2C(NACK) ' Read data with NACK
        STOP_I2C() ' End transaction
    Endif
End Function