/**
  ******************************************************************************
 *
 * @file        Sample_I2C_ByteMode_Simple.c
 *
 * @brief       This is the C code format sample file for I2C.
 *              include function :
 *                  I2C Module Initial : void Sample_I2C0_Init(void);
 *                  Bus Start : Sample_StatusTypeDef I2C_BusStart(I2C_Struct* I2Cx);
 *                  Master Bus Stop : Sample_StatusTypeDef I2C_Master_BusStop(I2C_Struct* I2Cx);
 *                  Data Transmit : Sample_StatusTypeDef I2C_Transmiter(I2C_Struct* I2Cx, uint8_t TxData);
 *                  Receive Data : Sample_StatusTypeDef I2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
 *                  Access 24C EEPROM Sample Code : void Sample_I2C0_Code(void);
 *
 * @par         Project
 *              MG32
 * @version     V1.05
 * @date        2023/06/26
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2023 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "Sample_I2C_ByteMode_Simple.h"

/* Private includes ----------------------------------------------------------*/
/* External functions --------------------------------------------------------*/

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/


/**
 *******************************************************************************
 * @brief       Initialize the I2C peripheral
 * @details     1 NVIC Config.
 *      \n      2 I2C Initial
 *      \n      2.1 I2C Output Clock Config 
 *      \n      2.2 I2C OwnAddress Config
 *      \n      2.3 I2C Interrupt Config
 *      \n      2.4 I2C Enable
 * @return      None
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Sample_I2C_Init();
 * @endcode     
 * @par         Modify
 *              Sample_I2C_Init(void)
 *******************************************************************************
 */
void Sample_I2C0_Init(void)
{
  // 1.0 I2c AFS Pin Config
    PIN_InitTypeDef PINX_InitStruct;

    PINX_InitStruct.PINX_Pin                = (PX_Pin_10 | PX_Pin_11);
    PINX_InitStruct.PINX_Mode               = PINX_Mode_OpenDrain_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Enable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_High;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_Alternate_Function = 2;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);

  // 2.1 I2C0 Output Clock Config
    //SCL Clock = CK_I2C_PR / Prescaler / Divider / (HT + LT), Must HT >=5 LT >= 4.
    I2C_Cmd(I2C0, DISABLE);
    I2C_SetClockSource(I2C0,I2C_CLK_SRC_PROC);          // CK_I2C0_PR : 22.1184MHz
    I2C_SetClockPrescaler(I2C0, I2C_CLK_PSC_2);         // 11.0592MHz
    I2C_SetClockDivider(I2C0, I2C_CLK_DIV_1);           // 11.0592MHz
    I2C_SetSCLHighTime(I2C0, 13);                       // High Time Must >= 5CLK, 
    I2C_SetSCLLowTime(I2C0, 13);                        // Low Time Must >= 4CLK
                                                        // SCL 394971.428Hz
    I2C_SetPreDriveTime(I2C0, I2C_PDRV_0T);

  // 2.2 I2C OwnAddress Config
    I2C_SlaveAddressDetect_Cmd(I2C0, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
    //I2C_SetSlaveAddress(I2C0, I2C_SADR_1, 0x00);        //
    //I2C_SetSlaveAddress(I2C0, I2C_SADR_2, 0x00);        //
    //I2C_GeneralCallAddress_Cmd(I2C0, DISABLE);          //

  // 2.3 Disable I2C Interrupt Config 
    I2C_IT_Config(I2C0, I2C_IT_EVENT, DISABLE);
    I2C_ITEA_Cmd(I2C0, DISABLE);

  // 2.4 I2C Enable
    I2C_Cmd(I2C0, ENABLE);

  // 3 NVIC Interrupt Config
    // NVIC_EnableIRQ(I2Cx_IRQn);
    // NVIC_SetPriority(I2Cx_IRQn, 3);                                         // Suggest SYSTICK Priority = 0
}

/**
 *******************************************************************************
 * @brief       I2C Output Bus Start
 * @details     Output Bus Start
 * @param[in]   I2Cx : I2C0 / 1
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
 *              I2C_BusStart(I2Cx);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_BusStart(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_BusStart(I2C_Struct* I2Cx)
{
    uint8_t lEventCode;

    lEventCode = (I2Cx->STA2.B[0] & 0xF8);
    if(lEventCode != 0xF8)
    {
        while((I2Cx->STA2.B[1] & 0x01) == 0);
        lEventCode = (I2Cx->STA2.B[0] & 0xF8);
    }

    switch (lEventCode){
        case 0x08:
        case 0x10:
            return SUCCESS;

        default:

        case 0xF8:
            Set_STOP_CLR(I2Cx);
            Set_START_SET(I2Cx);
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            while((I2Cx->STA2.B[1] & 0x01) == 0);
            return SUCCESS;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Master Output Bus Stop
 * @details     Master Output Bus Stop
 * @param[in]   I2Cx : I2C0 / 1
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C_Master_BusStop(I2C0);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Master_BusStop(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_Master_BusStop(I2C_Struct* I2Cx)
{
    uint8_t lEventCode;

    while((I2Cx->STA2.B[1] & 0x01) == 0);
    lEventCode = (I2Cx->STA2.B[0] & 0xF8);

    switch (lEventCode){
        case 0xF8:
        case 0xA0:
            return SUCCESS;

        default:
            Set_STA_STO_AA_010(I2Cx);
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            while(((I2Cx)->CR2.B[0] & I2C_CR2_STO_mask_b0) != 0);
            return SUCCESS;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Transmiter Data
 * @details     Transmiter Data
 * @param[in]   I2Cx : I2C0 / 1
 * @param[in]   TxData : Value of Output Data
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C_Transmiter(I2C0, (uint8_t *)&TxBuff)
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Transmiter(I2C_Struct* I2Cx, uint8_t TxData)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_Transmiter(I2C_Struct* I2Cx, uint8_t TxData)
{
    uint8_t lEventCode;

    while((I2Cx->STA2.B[1] & 0x01) == 0);
    lEventCode = (I2Cx->STA2.B[0] & 0xF8);

    switch (lEventCode){
        case 0x08:
        case 0x10:
            Set_START_CLR(I2Cx);

          #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
            __attribute__((fallthrough));
          #endif

        case 0x18:
        case 0x20:
        case 0x28:
        case 0x30:
        case 0xB8:
            Set_ASSERT_ACKNOWLEDGE_SET(I2Cx);
            I2C_SendSBUF(I2Cx, TxData);

          #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
            __attribute__((fallthrough));
          #endif

        case 0xA8:
        case 0xB0:
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            return SUCCESS;

        case 0xC0:
        default:
            return FAILURE;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Receive Data
 * @details     Receive Data
 * @param[in]   I2Cx : I2C0 / 1
 * @param[out]  RxData : Value of Receive Data.
 * @param[in]   Acknowledge : Freeback ACK / NACK to Transmiter.
 *          \n  0 : NACK
 *          \n  1 : ACK
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C_Receive(I2C0, (uint8_t *)&RxBuff, I2C_ACK);
                I2C_Receive(I2C0, (uint8_t *)&RxBuff, I2C_NACK);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
{
    uint8_t lEventCode;

    while((I2Cx->STA2.B[1] & 0x01) == 0);
    lEventCode = (I2Cx->STA2.B[0] & 0xF8);
    switch (lEventCode){
        case 0x40:
        case 0x50:
        case 0x80:
        case 0x90:
            if(Acknowledge != 0)
                Set_ASSERT_ACKNOWLEDGE_SET(I2Cx);
            else
                Set_ASSERT_ACKNOWLEDGE_CLR(I2Cx);

        #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
        __attribute__((fallthrough));
        #endif

        case 0x58:
        case 0x88:
        case 0x98:
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            while((I2Cx->STA2.B[1] & 0x01) == 0);
            *RxData = I2Cx->SBUF.B[0];
            return SUCCESS;

        case 0x60:
        case 0x68:
        case 0x70:
        case 0x78:
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            return SUCCESS;

        case 0xA0:
            I2Cx->STA2.B[1] = I2C_STA2_EVENTF2_mask_b1;
            return FAILURE;
        default:
            return FAILURE;
    }
}

/**
 *******************************************************************************
 * @brief       Sample I2C0 Code
 * @details     I2C0 Sample Code
 * @return      None
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C0_Receive();
 * @endcode     
 * @par         Modify
 *              Sample_I2C0_SampleCode()
 *******************************************************************************
 */
void Sample_I2C0_Code(void)
{
    uint8_t lTemp = 0;

//-----------------------------------------------------------------------------
    I2C_BusStart(I2C0);                     // Output Bus Start

    lTemp = 0xA0;
    I2C_Transmiter(I2C0, lTemp);            // Output Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    lTemp = 0x33;
    I2C_Transmiter(I2C0, lTemp);            // Output Data1 0x33

    lTemp = 0xCC;
    I2C_Transmiter(I2C0, lTemp);            // Output Data2 0xCC

    lTemp = 0x55;
    I2C_Transmiter(I2C0, lTemp);            // Output Data3 0x55

    lTemp = 0xAA;
    I2C_Transmiter(I2C0, lTemp);            // Output Data4 0xAA

    lTemp = 0x66;
    I2C_Transmiter(I2C0, lTemp);            // Output Data5 0x66

    lTemp = 0x99;
    I2C_Transmiter(I2C0, lTemp);            // Output Data6 0x99

    lTemp = 0xFF;
    I2C_Transmiter(I2C0, lTemp);            // Output Data7 0xFF

    lTemp = 0xFF;
    I2C_Transmiter(I2C0, lTemp);            // Output Data8 0xFF

    I2C_Master_BusStop(I2C0);               // Output Bus Stop

    Delay(5);                               // Write cycle time (byte or page)

//-----------------------------------------------------------------------------
    I2C_BusStart(I2C0);                     // Output Bus Start

    lTemp = 0xA0;
    I2C_Transmiter(I2C0, lTemp);            // Output Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    lTemp = 0x08;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output Data1 0x00

    lTemp = 0x11;
    I2C_Transmiter(I2C0, lTemp);            // Output Data2 0x11

    lTemp = 0x22;
    I2C_Transmiter(I2C0, lTemp);            // Output Data3 0x22

    lTemp = 0x33;
    I2C_Transmiter(I2C0, lTemp);            // Output Data4 0x33

    lTemp = 0x44;
    I2C_Transmiter(I2C0, lTemp);            // Output Data5 0x44

    lTemp = 0x55;
    I2C_Transmiter(I2C0, lTemp);            // Output Data6 0x55

    lTemp = 0x66;
    I2C_Transmiter(I2C0, lTemp);            // Output Data7 0x66

    lTemp = 0x77;
    I2C_Transmiter(I2C0, lTemp);            // Output Data8 0x77

    I2C_Master_BusStop(I2C0);               // Output Bus Stop

    Delay(5);                               // Write cycle time (byte or page)

//-----------------------------------------------------------------------------
    I2C_BusStart(I2C0);                     // Output Repeat Start

    lTemp = 0xA0;
    I2C_Transmiter(I2C0, lTemp);            // Output Device Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    lTemp = 0x00;
    I2C_Transmiter(I2C0, lTemp);            // Output 24C Memory Address 0x00

    I2C_BusStart(I2C0);                     // Output Repeat Start
    lTemp = 0xA1;
    I2C_Transmiter(I2C0, lTemp);            // Output Device Address 0xA1, Transmiter Slave Device Addree and Read / Write

    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 0
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 1
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 2
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 3
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 4
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 5
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 6
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 7
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 8
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 9
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 10
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 11
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 12
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 13
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 14
    I2C_Receive(I2C0, &lTemp, I2C_ACK);      // Receive Data Byte 15

    I2C_Receive(I2C0, &lTemp, I2C_NACK);     // Receive Data Byte 16  (Last Byte).
    I2C_Master_BusStop(I2C0);
}


