//#############################################################################
//
// FILE:    i2c_ex1_master.c
//
// TITLE:   I2C Example Master.
//
// VERSION: 1.0.0
//
// DATE:    2025-01-15
//
//! \addtogroup bitfield_example_list
//! <h1>I2C master slave communication using bit-field and without FIFO </h1>
//!
//! This program shows how to use I2CA in master configuration.
//! This example uses polling and does not use interrupts or FIFO
//!
//! \b Requires two Control Cards - one configured as Master and other as Slave \n
//! \b Master will run the binary generated from "i2c_ex1_master.=uvprojx" \n
//! \b Slave will run the binary generated from "i2c_ex1_slave.uvprojx" \n
//! \b External \b Connections on Control Cards should be made as shown below \n
//!  ----------------------------------------------------------------
//!    Signal   |  I2CA on Board1      |  I2CA on Board 2
//!  -----------------------------------------------------------------
//!     SCL     | GPIO_PIN_SCLA        |  GPIO_PIN_SCLA
//!     SDA     | GPIO_PIN_SDAA        |  GPIO_PIN_SDAA
//!     GND     |   GND                |   GND
//!  -----------------------------------------------------------------
//!
//! Example1: Master Transmitter and Slave Receiver
//! Example2: Master Receiver and Slave Transmitter
//! Example3: Master Transmitter and Slave Receiver
//!           followed by Master Receiver and Slave Transmitter
//! Example4: Master Receiver and Slave Transmitter
//!           followed by Master Transmitter and Slave Receiver
//!
//! \b Watch \b Variables in memory window\n
//!  - \b I2CA_TXdata
//!  - \b I2CA_RXdata
//!
//
//###########################################################################
//
//
// $Copyright:
// Copyright (C) 2024 Geehy Semiconductor - http://www.geehy.com/
// Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//
// Modifications:
// - 2024-07-08:
// 1. Updated interrupt handling to use NVIC functions.
//
//###########################################################################

//
// Included Files
//
#include "g32r501_project.h"

//
// Defines
//
#define I2C_SLAVE_ADDRESS 0x6AU
#define I2C_OWN_ADDRESS 0x30U
#define MAX_BUFFER_SIZE 0x10
#define I2C_NUMBYTES    0x2U

//
// I2C GPIO pins
//
#define GPIO_PIN_SDAA        26U  // GPIO number for I2C SDAA
#define GPIO_PIN_SCLA        27U  // GPIO number for I2C SCLA

//
// Globals
//
uint16_t I2C_TXdata[MAX_BUFFER_SIZE];
uint16_t I2C_RXdata[MAX_BUFFER_SIZE];


//
// Function Prototypes
//
void I2CMaster_Init(uint16_t I2CSlave_OwnAddress, uint16_t I2CSlave_Address);
void I2CWrite(uint16_t slaveAddr, uint16_t byteCount, bool sendStopCondition);
uint16_t I2CRead(uint16_t slaveAddr, uint16_t byteCount, bool sendStopCondition);


//
// Main
//
void example_main(void)
{
    //
    // Locals
    //
    uint16_t index = 0U;
    uint16_t count = 0U;

    //
    // Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    //
    InitSysCtrl();

    //
    // Initialize GPIO
    //
    InitGpio();

    //
    //Configure I2C pins
    //
    GPIO_SetupPinMux(GPIO_PIN_SDAA, GPIO_MUX_CPU0, 11);
    GPIO_SetupPinOptions(GPIO_PIN_SDAA, GPIO_OUTPUT, GPIO_PULLUP);
    GPIO_SetupPinMux(GPIO_PIN_SCLA, GPIO_MUX_CPU0, 11);
    GPIO_SetupPinOptions(GPIO_PIN_SCLA, GPIO_OUTPUT, GPIO_PULLUP);


    //
    //Initialize the NVIC control registers to their default state.
    //The default state is all NVIC interrupts disabled and flags
    //are cleared.
    //
    Interrupt_initModule();

    //
    //Initialize the NVIC vector table with pointers to the shell Interrupt
    //Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Set the buffer to some default non-zero value
    //
    for (index=0; index<MAX_BUFFER_SIZE;index++)
    {
        I2C_RXdata[index] = 0xBAADU;
        I2C_TXdata[index] = 0x11 * (index+1);
    }

    //
    // Initialize I2C Module as Master Transmitter
    //
    I2CMaster_Init(I2C_OWN_ADDRESS,I2C_SLAVE_ADDRESS);

    //
    // Example 1 : Master as a Transmitter , writes two bytes
    //
    I2CWrite(I2C_SLAVE_ADDRESS, I2C_NUMBYTES, true);

    //
    // Wait for I2C bus to clear
    //
    while(I2caRegs.I2CCTRL.bit.STOGEN !=0x0);
    while(I2caRegs.I2CSTS.bit.BBSYFLG !=0x0);

    //
    //If code reached below ESTOP0, Example 1 worked correctly
    //Observe the contents of I2CA_TXdata and I2CB_RXdata in memory browser
    // Move the PC to next line
    //
    ESTOP0;

    //
    // Example 2 : Master as a Receiver , receives two bytes
    //
    count = I2CRead(I2C_SLAVE_ADDRESS,I2C_NUMBYTES,true);

    //
    // Wait for I2C bus to clear
    //
    while(I2caRegs.I2CCTRL.bit.STOGEN !=0x0);
    while(I2caRegs.I2CSTS.bit.BBSYFLG !=0x0);

    //
    //If code reached below ESTOP0, Example 2 worked correctly
    //Observe the contents of I2CA_TXdata and I2CB_RXdata in memory browser
    // Move the PC to next line
    //
    ESTOP0;

    //
    //clear the Rx buffer
    //
    for (index=0; index<count;index++)
    {
        I2C_RXdata[index] = 0xBAADU;
    }

    //
    // Example 3 : Master Transmitter followed by Master Receiver
    //
    I2CWrite(I2C_SLAVE_ADDRESS, I2C_NUMBYTES, false); //Write byte
    count = I2CRead(I2C_SLAVE_ADDRESS,I2C_NUMBYTES,true);

    //
    // Wait for I2C bus to clear
    //
    while(I2caRegs.I2CCTRL.bit.STOGEN !=0x0);
    while(I2caRegs.I2CSTS.bit.BBSYFLG !=0x0);

    //
    //If code reached below ESTOP0, Example 3 worked correctly
    //Observe the contents of I2CA_TXdata and I2CB_RXdata in memory browser
    // Move the PC to next line    
    //
    ESTOP0;

    //
    //clear the Rx buffer
    //
    for (index=0; index<count;index++)
    {
        I2C_RXdata[index] = 0xBAADU;
    }

    //
    // Exampel 4: Master Receiver followed by Master Receiver
    //
    count =I2CRead(I2C_SLAVE_ADDRESS, I2C_NUMBYTES, false); //Write byte
    I2CWrite(I2C_SLAVE_ADDRESS,I2C_NUMBYTES,true);

    //
    // Wait for I2C bus to clear
    //
    while(I2caRegs.I2CCTRL.bit.STOGEN !=0x0);
    while(I2caRegs.I2CSTS.bit.BBSYFLG !=0x0);

    //
    //If code reached below ESTOP0, Example 4 worked correctly
    //Observe the contents of I2CA_TXdata and I2CB_RXdata in memory browser
    // Move the PC to next line
    //
    ESTOP0;

    //
    //clear the Rx buffer
    //
    for (index=0; index<count;index++)
    {
        I2C_RXdata[index] = 0xBAADU;
    }

    //
    // Loop forever.
    //
    while(1)
    {

    }

}

//
// Function to configure I2CA as Master Transmitter.
//
void I2CMaster_Init(uint16_t I2C_OwnAddress, uint16_t I2CSlave_Address)
{
    WRPRT_DISABLE;
    //
    // Must put I2C into reset before configuring it
    //
    I2caRegs.I2CCTRL.all &= ~(0x20U);

    //
    // I2C configuration. Use a 400kHz I2CCLK with a 50% duty cycle.
    //
    //I2C_initMaster(base, DEVICE_APBCLK_FREQ, 400000, I2C_DUTYCYCLE_50);
    I2caRegs.I2CPSC.all = 0xB;        // Prescaler - need 7-12 Mhz on module clk
    I2caRegs.I2CCLKL = 0x7;          // NOTE: must be non zero
    I2caRegs.I2CCLKH = 0x8;           // NOTE: must be non zero


    //
    // Configure Master as a Transmitter
    //
    I2caRegs.I2CCTRL.bit.MSCFG = 0x1;
    I2caRegs.I2CCTRL.bit.RXTXCFG = 0x1;

    //
    // Set data count
    //
    I2caRegs.I2CCNT = I2C_NUMBYTES;

    //
    // Set the bit count to 8 bits per data byte
    //
    I2caRegs.I2CCTRL.bit.DBSEL = 0x0U;

    //
    // Configure slave and own address
    //
    I2caRegs.I2COADDR.all = I2C_OwnAddress;         // Own address
    I2caRegs.I2CSADDR.all = I2CSlave_Address;       // Slave address

    //
    // Set emulation mode to FREEEN
    //
    I2caRegs.I2CCTRL.bit.FREEEN = 0x1;

    //
    //Clear all status
    //
    I2caRegs.I2CSTS.all = 0xFFFF;

    //
    // Enable I2C Interrupts- RRDY
    //
    I2caRegs.I2CIREN.all = 0x08;

    //
    // Take I2C out of reset
    //
    I2caRegs.I2CCTRL.all |= 0x0020;


}

//
// Function to send data over I2C.
//
void I2CWrite(uint16_t slaveAddr, uint16_t byteCount, bool sendStopCondition)
{

    //
    // Locals
    //
    uint16_t index = 0;

    //
    // Configure slave address
    //
    I2caRegs.I2CSADDR.all = slaveAddr;      // Slave address

    //
    // Configure I2C as Master Transmitter
    //
    I2caRegs.I2CCTRL.bit.MSCFG = 0x1;
    I2caRegs.I2CCTRL.bit.RXTXCFG = 0x1;

    //
    //Set Data Count
    //
    I2caRegs.I2CCNT = byteCount;

    //
    // send Start condition
    //
    I2caRegs.I2CCTRL.bit.STAGEN = 0x1;

    //
    //transmit the bytes
    //
    for(index=0; index < I2C_NUMBYTES; index++)
    {
        I2caRegs.I2CTXD.all= I2C_TXdata[index];
        //
        //wait till byte is sent
        //
        while(I2caRegs.I2CSTS.bit.BTXCFLG != 0x1);
        //
        //clear the byte sent
        //
        I2caRegs.I2CSTS.bit.BTXCFLG = 0x1;
    }

    //
    // Send STOP condition if specified
    //
    if(sendStopCondition)
    {
        I2caRegs.I2CCTRL.bit.STOGEN = 0x1;
        while(I2caRegs.I2CCTRL.bit.STOGEN != 0x0);

        I2caRegs.I2CSTS.bit.BTXCFLG = 0x1;
    }
}

//
// Function to read data over I2C. Returns the number of bytes read
//
uint16_t I2CRead(uint16_t slaveAddr, uint16_t byteCount, bool sendStopCondition)
{
    //
    // Configure slave address
    //
    I2caRegs.I2CSADDR.all = slaveAddr;

    //
    // Configure I2C in Master Receiver mode
    //
    I2caRegs.I2CCTRL.bit.MSCFG = 0x1;
    I2caRegs.I2CCTRL.bit.RXTXCFG = 0x0;

    //
    //Set Data Count
    //
    //I2caRegs.I2CCNT = byteCount;

    //
    // send Start condition
    //
    I2caRegs.I2CCTRL.bit.STAGEN = 0x1;

    uint16_t count = 0;

    //
    // Read the received data into RX buffer
    //
    while(count < I2C_NUMBYTES)
    {
        if(I2caRegs.I2CSTS.bit.RXDIFLG ==0x1)
        {
            I2C_RXdata[count] = I2caRegs.I2CRXD.all;
            count++;
        }
    }

    //
    // Send STOP condition
    //
    if(sendStopCondition)
    {
        I2caRegs.I2CCTRL.bit.STOGEN = 0x1;
        while(I2caRegs.I2CCTRL.bit.STOGEN != 0x0);

        I2caRegs.I2CSTS.bit.BTXCFLG = 0x1;

    }
    return count;
}

//
//
// End of File
//
