/*
 * i2c0.c
 *
 *  Created on: Dec 1, 2022
 *      Author: thomm
 */


#include <stdint.h>
#include <stdbool.h>
#include "system.h"
#include "user_io.h"
#include "uartstdio.h"  // User local version with larger RX buffer
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"

#include "i2c0.h"


int i2c0_initFlg = 0;

/******************************************************************************
 * Initialize and configure I2C module in TIVA tm4c123gh6pge
 *            MFET uses I2C0_BASE on PB2/PB3, the other i2c periph base addr are not used
 *
 * Parameters:
 *          ui32Base: I2Cx base address. The address is one of the following values:
 *              I2C0_BASE, I2C1_BASE, I2C2_BASE, I2C3_BASE.
 *
 *      bFast:
 *              true : I2C will run in fast mode (400kbps)
 *              false: I2C will run in standard mode (100kbps)
 *
 * Return: none
 *****************************************************************************/
void i2c0_init(bool bFast)
{
    if(i2c0_initFlg > 0)        // if init'd, then return
        return;

    //ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);      // this is done prior in init.c

    //enable onchip I2C peripheral
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    //reset I2C module
    ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    // Configure the pin muxing for I2C0 functions on port PB2(SCL) and PB3(SDA).
    ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);     // This is the same on 144 pin part and 64pin part
    ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA);

    // Configure the appropriate pins to be I2C instead of GPIO.
    ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    //GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    //GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);


    ROM_GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    ROM_GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);

    // Initialize the I2C master - Transfer speed is defined depend on variable bFast
    ROM_I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), bFast);

    //clear I2C FIFOs
    HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;

    ROM_I2CMasterEnable(I2C0_BASE);      //I2C is ready to use

    i2c0_initFlg = 1;
}


uint8_t i2c0_read8(uint8_t i2c_addr, uint8_t reg_addr)
{
    uint8_t readByte = 0;

    if(i2c_addr > 127)
        i2c_addr /= 2;

    i2c0_read(i2c_addr, reg_addr, &readByte, 1);

    return(readByte);
}


uint16_t i2c0_read16(uint8_t i2c_addr, uint8_t reg_addr)
{
    uint16_t readShort = 0;

    if(i2c_addr > 127)
        i2c_addr /= 2;

    i2c0_read(i2c_addr, reg_addr, (uint8_t *)&readShort, 2);

    return(readShort);
}


int i2c0_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data, uint8_t length)
{
    int i;

    if(i2c_addr > 127)
        i2c_addr /= 2;

    // write mode, set slave address
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, i2c_addr, false);

    // set slave register
    ROM_I2CMasterDataPut(I2C0_BASE, reg_addr);

    // send request
    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while (ROM_I2CMasterBusy(I2C0_BASE))
    {
    }

    // change to read mode
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, i2c_addr, true);

    // read one or a number of bytes
    for (i = 0; i < length; i++)
    {
        if (length == 1)
        {
            ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
        }
        else
        {
            if (i == 0)
            {
                ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
            }
            else if (i == length - 1)
            {
                ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
            }
            else
            {
                ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
            }
        }
        while (ROM_I2CMasterBusy(I2C0_BASE))
        {
        }
        data[i] = ROM_I2CMasterDataGet(I2C0_BASE);
    }

    return 1;
}



#ifdef CODEFROMINTERNET
https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/610475/tm4c129enczad-i2c-write-transaction-not-latched-into-slave-device-written-to?ReplyFilter=Answers&ReplySortBy=Answers&ReplySortOrder=Descending

///////////////////////////////

//Set up for write to slave

  //SlaveAddress = 32;  //CTRL_REG1 address (x20)

  I2CMasterSlaveAddrSet(I2C2_BASE, Board_TM4C129_ACCEL_ADDR, false);  //false = write.

  SysCtlDelay(1000); // Allow Busy flag to set (TM4C129 issue)

  while(I2CMasterBusBusy(I2C2_BASE));

//write data to slave

  I2CMasterDataPut(I2C2_BASE, SlaveAddress);



  I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_START);   //Per CB1_Mobile




  SysCtlDelay(1000); // Allow Busy flag to set (TM4C129 issue)

  I2CMasterDataPut(I2C2_BASE, MasterTxData_S);  //write updated CTRL_REG1 setting




  //I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_SEND);

  I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);     //Per CB1_Mobile




  SysCtlDelay(1000); // Allow Busy flag to set (TM4C129 issue)

  I2CMasterDataPut(I2C2_BASE, SlaveAddress);

  I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);    //Per CB1_Mobile

  SysCtlDelay(1000); // Allow Busy flag to set (TM4C129 issue)

  while(I2CMasterBusBusy(I2C2_BASE));

////////////////////////////////

#endif







int i2c0_write_reg_byte(uint8_t i2c_addr, uint8_t reg_addr, uint8_t data)
//int i2c0_write8(uint8_t i2c_addr, uint8_t reg_addr, uint8_t data)
{
    if(i2c_addr > 127)
        i2c_addr /= 2;

    // write mode, set slave address
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, i2c_addr, FALSE);      // FALSE indicates a write?

    // set slave register
    ROM_I2CMasterDataPut(I2C0_BASE, reg_addr);
    //while (ROM_I2CMasterBusy(I2C0_BASE));       // is this check necessary

    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while (ROM_I2CMasterBusy(I2C0_BASE));

    ROM_I2CMasterDataPut(I2C0_BASE, data);

    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    while (ROM_I2CMasterBusy(I2C0_BASE));

    //ROM_I2CMasterDataPut(I2C0_BASE, reg_addr);  //???? why send reg_addr again???

    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    while (ROM_I2CMasterBusy(I2C0_BASE));

    return 1;

#ifdef OLDCODE
    if(i2c_addr > 127)
        i2c_addr /= 2;

    // write mode, set slave address
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, i2c_addr, FALSE);      // FALSE indicates a write?

    // set slave register
    ROM_I2CMasterDataPut(I2C0_BASE, reg_addr);
    //while (ROM_I2CMasterBusy(I2C0_BASE));       // is this check necessary




    // send request
    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);  //ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while (ROM_I2CMasterBusy(I2C0_BASE))
    {
    }

    // write data
    ROM_I2CMasterDataPut(I2C0_BASE, data);

    //ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    while (ROM_I2CMasterBusy(I2C0_BASE))
    {
    }

    return 1;
#endif
}

int i2c0_write16(uint8_t i2c_addr, uint8_t reg_addr, uint16_t data16)
{
    if(i2c_addr > 127)
        i2c_addr /= 2;

    return(i2c0_write(i2c_addr, reg_addr, (uint8_t *)&data16, 2));
}

int i2c0_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data, uint8_t length)
{
    unsigned int indx;

    IntMasterDisable();

    if(i2c_addr > 127)
        i2c_addr /= 2;

    //Master is initiating a write to the slave, set slave i2c address
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, i2c_addr, FALSE); // FALSE indicates a write

    //write the single byte of the reg addr
    ROM_I2CMasterDataPut(I2C0_BASE, reg_addr);
    //while (ROM_I2CMasterBusy(I2C0_BASE));


    if (length == 1)        // was 0???  Does not make sense, check this case on i2c_fram
    {
        // Initiate send of character from Master to Slave (NEEDS TESTING)
        ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    }
    else
    {
        // Start the burst cycle, writing the address as the first byte.
        ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
        while (ROM_I2CMasterBusy(I2C0_BASE));         // wait for completion

        ROM_I2CMasterDataPut(I2C0_BASE, data[0]);

        for(indx=1; indx<length; indx++)        // loop is structured so that last dataPut is followed by SEND_FINISH
        {
            // Continue the burst write.
            ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
            // Write the next byte to the data register.
            while (ROM_I2CMasterBusy(I2C0_BASE));
            ROM_I2CMasterDataPut(I2C0_BASE, data[indx]);
        }
        // Finish the burst write.
        ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    }
    while (ROM_I2CMasterBusy(I2C0_BASE));

    IntMasterEnable();

    return 1;
}



int i2c0_busScan(void)
{
    unsigned char ucProbeAdress;
    unsigned long ulErrorState;

    //
    // There should be nothing active, but hey why not check
    //
    while(ROM_I2CMasterBusy(I2C0_BASE))
    {
    }

    uprintf("\r\nI2C0 Bus-Scan done...\r\n");

    //
    // I2C Addresses are 7-bit values
    // probe the address range of 0 to 127 to find I2C slave devices on the bus
    //
    for (ucProbeAdress = 0; ucProbeAdress < 127; ucProbeAdress++)
    {
        //
        // Tell the master module what address it will place on the bus when
        // writing to the slave.
        //
        ROM_I2CMasterSlaveAddrSet(I2C0_BASE, ucProbeAdress, false);

        //
        // Place the command to be sent in the data register.
        //
        ROM_I2CMasterDataPut(I2C0_BASE, 0x00);

        //
        // Initiate send of data from the master.
        //
        ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

        while(ROM_I2CMasterBusy(I2C0_BASE));

        //
        // Read the I2C Master Control/Status (I2CMCS) Register to a local
        // variable
        //
        ulErrorState = ROM_I2CMasterErr(I2C0_BASE);

        //
        // Examining the content I2C Master Control/Status (I2CMCS) Register
        // to see if the ADRACK-Bit (Acknowledge Address) is TRUE (1)
        // ( 1: The transmitted address was not acknowledged by the slave)
        //
        if(ulErrorState & I2C_MASTER_ERR_ADDR_ACK)
        {
            //
            // device at selected address did not acknowledge --> there's no device
            // with this address present on the I2C bus

            uprintf("Address not found: 0x%02x - %3d\r\n",ucProbeAdress,ucProbeAdress);
            wait_consoleTx();
            //
            // Make some delay
            //
            //ROM_SysCtlDelay(1500000);
        }
        //
        // ( 0: The transmitted address was acknowledged by the slave)
        //
        else
        {
            //
            // device at selected address acknowledged --> there is a device
            // with this address present on the I2C bus

            uprintf("Address found:     0x%2x - %3d   (0x%02x)\r\n",ucProbeAdress,ucProbeAdress,ucProbeAdress*2);
            //
            // Make some delay
            //
            //ROM_SysCtlDelay(1500000);
        }
    }


    uprintf("\r\nI2C0 Bus-Scan done...\r\n");

    return 1;
}



#ifdef NOCODE


int i2c0_read(uint8_t reg_addr, uint8_t* data, uint8_t length)
{

    // write mode, set slave address
    I2CMasterSlaveAddrSet(I2C0_BASE, BME280_I2C_ADDRESS, false);

    // set slave register
    I2CMasterDataPut(I2C0_BASE, reg_addr);

    // send request
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while (I2CMasterBusy(_i2cBase))
    {
    }

    // change to read mode
    I2CMasterSlaveAddrSet(I2C0_BASE, I2C_ADDRESS, true);

    // read one or a number of bytes
    for (int i = 0; i < length; i++)
    {
        if (length == 1)
        {
            I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
        }
        else
        {
            if (i == 0)
            {
                I2CMasterControl(I2C0_BASE,
                I2C_MASTER_CMD_BURST_RECEIVE_START);
            }
            else if (i == length - 1)
            {
                I2CMasterControl(I2C0_BASE,
                I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
            }
            else
            {
                I2CMasterControl(I2C0_BASE,
                I2C_MASTER_CMD_BURST_RECEIVE_CONT);
            }
        }
        while (I2CMasterBusy(I2C0_BASE))
        {
        }
        data[i] = I2CMasterDataGet(I2C0_BASE);
    }

    return 1;
}

int i2c0_write(uint8_t reg_addr, uint8_t data)
{

    // write mode, set slave address
    I2CMasterSlaveAddrSet(I2C0_BASE, I2C_ADDRESS, false);

    // set slave register
    I2CMasterDataPut(I2C0_BASE, reg_addr);

    // send request
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while (I2CMasterBusy(I2C0_BASE))
    {
    }

    // write data
    I2CMasterDataPut(I2C0_BASE, data);

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    while (I2CMasterBusy(_i2cBase))
    {
    }

}






const uint8_t lookup_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

void u32tohex(char * out, uint32_t n)
{
    out[0] = lookup_hex[n >> 28]; out[1] = lookup_hex[(n >> 24) & 15]; out[2] = lookup_hex[(n >> 20) & 15]; out[3] = lookup_hex[(n >> 16) & 15];
    out[4] = lookup_hex[(n >> 12) & 15]; out[5] = lookup_hex[(n >> 8) & 15]; out[6] = lookup_hex[(n >> 4) & 15]; out[7] = lookup_hex[n & 15];
}

void u16tohex(char * out, uint32_t n)
{
    out[0] = lookup_hex[(n >> 12) & 15]; out[1] = lookup_hex[(n >> 8) & 15]; out[2] = lookup_hex[(n >> 4) & 15]; out[3] = lookup_hex[n & 15];
}

void u8tohex(char * out, uint32_t n)
{
    out[0] = lookup_hex[(n >> 4) & 15]; out[1] = lookup_hex[n & 15];
}






































#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_gpio.h"
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
    //
    // Enable GPIO port A which is used for UART0 pins.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Configure the pin muxing for UART0 functions on port A0 and A1.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    //
    // Enable UART0 so that we can configure the clock.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Select the alternate (UART) function for these pins.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}

unsigned long
I2CBusScan(unsigned long ulI2CBase)
{
    unsigned char ucProbeAdress;
    unsigned long ucerrorstate;

    //
    // Wait until master module is done transferring.
    //
    while(ROM_I2CMasterBusy(ulI2CBase))
    {
    };
    //
    // I2C Addresses are 7-bit values
    // probe the address range of 0 to 127 to find I2C slave devices on the bus
    //
    for (ucProbeAdress = 0; ucProbeAdress < 127; ucProbeAdress++)
    {
        //
        // Tell the master module what address it will place on the bus when
        // writing to the slave.
        //
        ROM_I2CMasterSlaveAddrSet(ulI2CBase, ucProbeAdress, false);

        //
        // Place the command to be sent in the data register.
        //
        ROM_I2CMasterDataPut(ulI2CBase, 0x00);

        //
        // Initiate send of data from the master.
        //
        ROM_I2CMasterControl(ulI2CBase, I2C_MASTER_CMD_SINGLE_SEND);

        //
        // Make some delay
        //
        while(ROM_I2CMasterBusy(ulI2CBase));

        //
        // Read the I2C Master Control/Status (I2CMCS) Register to a local
        // variable
        //
        ucerrorstate = ROM_I2CMasterErr(ulI2CBase);

        //
        // Examining the content I2C Master Control/Status (I2CMCS) Register
        // to see if the ADRACK-Bit (Acknowledge Address) is TRUE (1)
        // ( 1: The transmitted address was not acknowledged by the slave)
        //
        if(ucerrorstate & I2C_MASTER_ERR_ADDR_ACK)
        {
            //
            // device at selected address did not acknowledge --> there's no device
            // with this address present on the I2C bus
            //
            //
            // Print a message to Stdio
            //
            UARTprintf("Address not found: 0x%2x - %3d\n",ucProbeAdress,ucProbeAdress);
            //
            // Make some delay
            //
            //ROM_SysCtlDelay(1500000);
        }
        //
        // ( 0: The transmitted address was acknowledged by the slave)
        //
        else
        {
            //
            // device at selected address acknowledged --> there is a device
            // with this address present on the I2C bus
            //
            //
            // Print a message to Stdio
            //
            UARTprintf("Address found: 0x%2x - %3d\n",ucProbeAdress,ucProbeAdress);
            //
            // Make some delay
            //
            ROM_SysCtlDelay(1500000);
        }
    }

    //
    //
    // Print a message to Stdio
    //
    UARTprintf("I2C Bus-Scan done...\n");
    //
    // Return 1 if there is no error.
    //
    return 1;
}

void I2CSetup(void)
{
        //enable I2C module 0
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
        //enable GPIO peripheral that contains I2C 0
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        //reset module      ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
        // Configure the pin muxing for I2C0 functions on port B2 and B3.
        ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
        ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA);
        // Select the I2C function for these pins.
        ROM_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

        HWREG(GPIO_PORTB_BASE+0x510) |= 0xC;

        // Enable and initialize the I2C0 master module.  Use the system clock for
        // the I2C0 module.  The last parameter sets the I2C data transfer rate.
        // If false the data rate is set to 100kbps and if true the data rate will
        // be set to 400kbps.
        ROM_I2CMasterInitExpClk(I2C0_BASE, 80000000, false);


}

void main(void)
{

    //
    // Set the clocking to run directly from the external crystal/oscillator.
    // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    // crystal on your board.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_OSC | SYSCTL_OSC_INT |
                   SYSCTL_XTAL_16MHZ);

    InitConsole();
    I2CSetup();
    UARTprintf("I2C Bus-Scan begin...\n");
    I2CBusScan(I2C0_BASE);

    while (1);

}




#endif
