/**
 ******************************************************************************
 *
 * @file        Sample_I2C_withDMA.c
 *
 * @brief       This file provides firmware functions to manage the following 
 *              functionalities of the DMA peripheral:
 *
 * @par         Project
 *              MG32
 * @version     V1.04
 * @date        2023/05/29
 * @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 "MG32_DRV.h"

/* External functions --------------------------------------------------------*/

/* Exported typedef ----------------------------------------------------------*/
/** 
  * @enum   SMP_StatusTypeDef
  * @brief  SMP Status structures definition  
  */
typedef enum{
    SMP_SUCCESS  = 0x00,    /*!< Success    */
    SMP_FAILURE  = 0x01,    /*!< Failure    */
    SMP_OK       = 0x00,    /*!< OK         */
    SMP_ERROR    = 0x01,    /*!< Error      */
    SMP_BUSY     = 0x02,    /*!< Busy       */
    SMP_TIMEOUT  = 0x03,    /*!< Timout     */
}SMP_StatusTypeDef;

/* Exported macro ------------------------------------------------------------*/
/* Exported define -----------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions -------------------------------------------------------*/
SMP_StatusTypeDef SMP_DMA_Init(void);

SMP_StatusTypeDef SMP_I2C_Init_withDMA_Polling(I2C_Struct *I2Cx);
SMP_StatusTypeDef SMP_I2C_Master_Transmit_withDMA_Polling(I2C_Struct *I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint16_t *pRealTranSize);
SMP_StatusTypeDef SMP_I2C_Master_Receive_withDMA_Polling(I2C_Struct *I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint16_t *pRealTranSize);
SMP_StatusTypeDef SMP_I2C_Slave_Receive_withDMA_Polling(I2C_Struct *I2Cx, uint8_t *pData, uint16_t Size, uint16_t *MatchAddress, uint16_t *pRealTranSize);
SMP_StatusTypeDef SMP_I2C_Slave_Transmit_withDMA_Polling(I2C_Struct *I2Cx, uint8_t *pData, uint16_t Size, uint16_t *MatchAddress, uint16_t *pRealTranSize);

/* Private includes ----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t gI2C0_TxBuff[40] = {"Megawin MG32 I2C0 Tx"}; /*!< I2C0 Tx Buffer  */
uint8_t gI2C0_RxBuff[40];                                /*!< I2C0 Rx Buffer  */
uint8_t gI2C1_TxBuff[40] = {"Megawin MG32 I2C1 Tx"}; /*!< I2C1 Tx Buffer  */
uint8_t gI2C1_RxBuff[40];                                /*!< I2C1 Rx Buffer  */

/* Private function prototypes -----------------------------------------------*/

/* Private user code ---------------------------------------------------------*/

/**
 ******************************************************************************
 *
 * @brief  I2C use DMA Transfor Sample Code
 * 
 *
 ******************************************************************************
 */
void SMP_I2C_withDMA(void)
{
    SysTick_Config(48000000UL / 1000UL);    /* System Tick Configuration      */
    NVIC_SetPriority(SysTick_IRQn, 0UL);    /* set Priority for Systick Interrupt */

    SMP_DMA_Init();

    SMP_I2C_Init_withDMA_Polling(I2C0);
    SMP_I2C_Init_withDMA_Polling(I2C1);

    SMP_I2C_Master_Transmit_withDMA_Polling(I2C0, 0x02, (uint8_t *)(&gI2C0_TxBuff[0]), 10, (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Master_Transmit_withDMA_Polling(I2C0, 0x80, (uint8_t *)(&gI2C0_TxBuff[0]), 15, (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Master_Transmit_withDMA_Polling(I2C0, 0x02, (uint8_t *)(&gI2C0_TxBuff[0]), 20, (uint16_t *)(&gI2C0_RealTranSize)); // Expected 20, Real 17 Issue, Must Reset I2C.
    SMP_I2C_Master_Transmit_withDMA_Polling(I2C0, 0x80, (uint8_t *)(&gI2C0_TxBuff[0]), 10, (uint16_t *)(&gI2C0_RealTranSize));

    SMP_I2C_Master_Receive_withDMA_Polling(I2C0, 0x80, (uint8_t *)(&gI2C0_RxBuff[0]), 10, (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Master_Receive_withDMA_Polling(I2C0, 0x02, (uint8_t *)(&gI2C0_RxBuff[0]), 15, (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Master_Receive_withDMA_Polling(I2C0, 0x80, (uint8_t *)(&gI2C0_RxBuff[0]), 20, (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Master_Receive_withDMA_Polling(I2C0, 0x02, (uint8_t *)(&gI2C0_RxBuff[0]), 10, (uint16_t *)(&gI2C0_RealTranSize));

    SMP_I2C_Slave_Receive_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_RxBuff), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Slave_Receive_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_RxBuff), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Slave_Receive_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_RxBuff), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize));

    SMP_I2C_Slave_Transmit_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_TxBuff[0]), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize)); // Expected Issue, Must Reset I2C.
    SMP_I2C_Slave_Transmit_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_TxBuff[0]), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize));
    SMP_I2C_Slave_Transmit_withDMA_Polling(I2C1, (uint8_t *)(&gI2C1_TxBuff[0]), 40, (uint16_t *)(&gI2C0_MatchAddress), (uint16_t *)(&gI2C0_RealTranSize));
}


/**
 ******************************************************************************
 *
 * @brief  DMA Initial
 * @retval SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_DMA_Init(void)
{
    DMA->CR0.W = DMA_CR0_GPL_CHS_disable_w | \
                 DMA_CR0_FGBUS_SEL_1byte_w | \
                 DMA_CR0_PRI_MDS_level_w | \
                 0;

    DMA->CR0.W |= DMA_CR0_EN_enable_w;

    return SMP_OK;
}


/**
 ******************************************************************************
 *
 * @brief     Transmit in master mode an amount of data in non-blocking mode with Interrupt
 * @param[in] I2Cx: Pointer to a I2C_Struct structure that contains
 *                  the configuration information for the specified I2C.
 * @retval SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_I2C_Init_withDMA_Polling(I2C_Struct *I2Cx)
{
    if(I2Cx == I2C0)
    {
        // CSC Clock
        CSC->APB0.W |= CSC_APB0_I2C0_EN_mask_w;

        // DMA Config CH1 for I2C0 Tx M2P
        DMA->CH1A.W = DMA_CH1A_CH1_BSIZE_one_w | \
                      DMA_CH1A_CH1_PLS_lv3_w | \
                      DMA_CH1A_CH1_XMDS_disable_w | \
                      DMA_CH1A_CH1_LAST_not_w | \
                      DMA_CH1A_CH1_ADSEL_normal_w | \
                      DMA_CH1A_CH1_LOOP_disable_w | \
                      DMA_CH1A_CH1_HOLD_disable_w | \
                      0;

        DMA->CH1B.W = DMA_CH1B_CH1_XPIN_trg0_w | \
                      DMA_CH1B_CH1_DSYNC_disable_w | \
                      DMA_CH1B_CH1_SSYNC_disable_w | \
                      DMA_CH1B_CH1_DINC_disable_w | \
                      DMA_CH1B_CH1_SINC_enable_w | \
                      DMA_I2C0_TX << DMA_CH1B_CH1_DET_shift_w | \
                      DMA_MEM_Read << DMA_CH1B_CH1_SRC_shift_w | \
                      0;

        DMA->CH1A.W |= DMA_CH1A_CH1_EN_mask_w;

        // DMA Config CH2 for I2C0 Rx P2M
        DMA->CH2A.W = DMA_CH2A_CH2_BSIZE_one_w | \
                      DMA_CH2A_CH2_PLS_lv3_w | \
                      DMA_CH2A_CH2_XMDS_disable_w | \
                      DMA_CH2A_CH2_LAST_not_w | \
                      DMA_CH2A_CH2_ADSEL_normal_w | \
                      DMA_CH2A_CH2_LOOP_disable_w | \
                      DMA_CH2A_CH2_HOLD_disable_w | \
                      0;

        DMA->CH2B.W = DMA_CH2B_CH2_XPIN_trg0_w | \
                      DMA_CH2B_CH2_DSYNC_disable_w | \
                      DMA_CH2B_CH2_SSYNC_disable_w | \
                      DMA_CH2B_CH2_DINC_enable_w | \
                      DMA_CH2B_CH2_SINC_disable_w | \
                      DMA_MEM_Write << DMA_CH2B_CH2_DET_shift_w | \
                      DMA_I2C0_RX << DMA_CH2B_CH2_SRC_shift_w | \
                      0;

        DMA->CH2A.W |= DMA_CH2A_CH2_EN_mask_w;

        // GPIO Config
        PINB(10)->CR.W = PX_CR_IOM_odo_w | PX_CR_HS_enable_w | PX_CR_PU_disable_w | PX_CR_INV_disable_w | PX_CR_ODC_level0_w | PX_CR_FDIV_bypass_w | PX_CR_AFS_af2_w;
        PINB(11)->CR.W = PX_CR_IOM_odo_w | PX_CR_HS_enable_w | PX_CR_PU_disable_w | PX_CR_INV_disable_w | PX_CR_ODC_level0_w | PX_CR_FDIV_bypass_w | PX_CR_AFS_af2_w;
    }
    else if(I2Cx == I2C1)
    {
        // CSC Clock
        CSC->APB0.W |= CSC_APB0_I2C1_EN_mask_w;

        // DMA Config CH3 for I2C1 Tx M2P
        DMA->CH3A.W = DMA_CH3A_CH3_BSIZE_one_w | \
                      DMA_CH3A_CH3_PLS_lv3_w | \
                      DMA_CH3A_CH3_XMDS_disable_w | \
                      DMA_CH3A_CH3_LAST_not_w | \
                      DMA_CH3A_CH3_ADSEL_normal_w | \
                      DMA_CH3A_CH3_LOOP_disable_w | \
                      DMA_CH3A_CH3_HOLD_disable_w | \
                      0;

        DMA->CH3B.W = DMA_CH3B_CH3_XPIN_trg0_w | \
                      DMA_CH3B_CH3_DSYNC_disable_w | \
                      DMA_CH3B_CH3_SSYNC_disable_w | \
                      DMA_CH3B_CH3_DINC_disable_w | \
                      DMA_CH3B_CH3_SINC_enable_w | \
                      DMA_I2C1_TX << DMA_CH3B_CH3_DET_shift_w | \
                      DMA_MEM_Read << DMA_CH3B_CH3_SRC_shift_w | \
                      0;

        DMA->CH3A.W |= DMA_CH3A_CH3_EN_mask_w;

        // DMA Config CH4 for I2C1 Rx P2M
        DMA->CH4A.W = DMA_CH4A_CH4_BSIZE_one_w | \
                      DMA_CH4A_CH4_PLS_lv3_w | \
                      DMA_CH4A_CH4_XMDS_disable_w | \
                      DMA_CH4A_CH4_LAST_not_w | \
                      DMA_CH4A_CH4_ADSEL_normal_w | \
                      DMA_CH4A_CH4_LOOP_disable_w | \
                      DMA_CH4A_CH4_HOLD_disable_w | \
                      0;

        DMA->CH4B.W = DMA_CH4B_CH4_XPIN_trg0_w | \
                      DMA_CH4B_CH4_DSYNC_disable_w | \
                      DMA_CH4B_CH4_SSYNC_disable_w | \
                      DMA_CH4B_CH4_DINC_enable_w | \
                      DMA_CH4B_CH4_SINC_disable_w | \
                      DMA_MEM_Write << DMA_CH4B_CH4_DET_shift_w | \
                      DMA_I2C1_RX << DMA_CH4B_CH4_SRC_shift_w | \
                      0;

        DMA->CH4A.W |= DMA_CH4A_CH4_EN_mask_w;

        // GPIO Config
        PINC(10)->CR.W = PX_CR_IOM_odo_w | PX_CR_HS_enable_w | PX_CR_PU_disable_w | PX_CR_INV_disable_w | PX_CR_ODC_level2_w | PX_CR_FDIV_bypass_w | PX_CR_AFS_af2_w;
        PINC(11)->CR.W = PX_CR_IOM_odo_w | PX_CR_HS_enable_w | PX_CR_PU_disable_w | PX_CR_INV_disable_w | PX_CR_ODC_level2_w | PX_CR_FDIV_bypass_w | PX_CR_AFS_af2_w;
    }
    else
        return SMP_ERROR;

    I2Cx->CR0.W = 0;

  //SCL Clock = CK_I2C_PR / Prescaler / Divider / (HT + LT), Must HT >=5 LT >= 4.
    __I2C_SetClockSource(I2Cx, I2C_CLK_SRC_PROC);       // I2C Clock Source from CK_I2C0_PR
    __I2C_SetClockPrescaler(I2Cx, I2C_CLK_PSC_2);
    __I2C_SetClockDivider(I2Cx, I2C_CLK_DIV_1);
    __I2C_SetSCLHighTime(I2Cx, 13);                     // High Time Must >= 5CLK, 
    __I2C_SetSCLLowTime(I2Cx, 13);                      // Low Time Must >= 4CLK
                                                        // SCL 
    I2C_SetPreDriveTime(I2Cx, I2C_PDRV_0T);

//    if(I2Cx == I2C0)
//    {
//    }
//    else if(I2Cx == I2C1)
//    {
    // I2C OwnAddress Config
        I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
        I2C_SetSlaveAddress(I2Cx, I2C_SADR_1, 0x02);        //
        I2C_SetSlaveAddress(I2Cx, I2C_SADR_2, 0x80);        //
        //I2C_GeneralCallAddress_Cmd(I2Cx, DISABLE);          //

        I2C_SetSlaveAddress1Mask(I2Cx, 0xFE);

        //I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), ENABLE);
//    }


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

  // I2C Enable
    I2C_Cmd(I2Cx, ENABLE);

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

/**
 ******************************************************************************
 *
 * @brief      Transmit in master mode an amount of data in non-blocking mode with Interrupt
 * @param[in]  I2Cx: Pointer to a I2C_Struct structure that contains
 *                   the configuration information for the specified I2C.
 * @param[in]  DevAddress: Target device address
 * @param[in]  pData: Pointer to data buffer
 * @param[in]  Size: Amount of data to be sent
 * @param[out] pRealTranSize
 * @retval SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_I2C_Master_Transmit_withDMA_Polling(I2C_Struct *I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint16_t *pRealTranSize)
{
    uint8_t lEVENTtemp;
    uint16_t lSendDataLength;

    if((I2Cx->STA.W & I2C_STA_BUSYF_mask_w) != 0)
        return SMP_BUSY;

    // DMA TX Config Data Source and Length
    if(I2Cx == I2C0)
    {
        DMA->CH1A.W &= ~DMA_CH1A_CH1_EN_mask_w;
        __ISB();
        DMA->CH1A.W |= DMA_CH1A_CH1_EN_mask_w;

        DMA->CH1NUM.W = Size;
        DMA->CH1SSA.W = (uint32_t)pData;
        DMA->CH1A.W |= DMA_CH1A_CH1_REQ_enable_w;
    }
    else if(I2Cx == I2C1)
    {
        DMA->CH3A.W &= ~DMA_CH3A_CH3_EN_mask_w;
        __ISB();
        DMA->CH3A.W |= DMA_CH3A_CH3_EN_mask_w;

        DMA->CH3NUM.W = Size;
        DMA->CH3SSA.W = (uint32_t)pData;
        DMA->CH3A.W |= DMA_CH3A_CH3_REQ_enable_w;
    }
    else
        return SMP_ERROR;

    // Output BUS START
    __I2C_STA_1(I2Cx);
    __I2C_WaitEventFlag(I2Cx);
    __I2C_STA_0(I2Cx);
    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    if(lEVENTtemp != 0x08)
    {
        __I2C_ClearEventFlag(I2Cx);
        return SMP_ERROR;
    }

    // Output Device Address
    __I2C_SendSBUF(I2Cx, (((uint8_t)DevAddress) & 0xFE));
    __I2C_ClearEventFlag(I2Cx);
    __I2C_WaitEventFlag(I2Cx);

    // Check EVENT match Slave Receive Mode.
    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    switch(lEVENTtemp){
        case 0x00 : // Bus Error
                    *pRealTranSize = 0;
                    __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                    __I2C_STO_1(I2Cx);
                    __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x18 : // SLA+R has been transmitted  ACK has been received.
                    break;

        case 0x20 : // Device Address Not ACK.
                    *pRealTranSize = 0;
                    __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                    __I2C_STO_1(I2Cx);
                    __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x38 : // Arbitration lost
                    __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
        case 0x10 : // Repeat Start
                    *pRealTranSize = 0;
                    __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x68 : // Arbitration lost and Address match, Slave Receive Mode.
        case 0x78 : // Arbitration lost and Address match, Slave Receive General Call Mode.
        case 0xB0 : // Arbitration lost and Address match, Slave Transmitter Mode.
                    *pRealTranSize = 0;
                    __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
                    //__I2C_ClearEventFlag(I2Cx);
        default :
                    return SMP_ERROR;
    }

    // Set Last Data Byte to STOP
    __I2C_PreSet_STA_STO_AA_010(I2Cx);

    // Enable I2C CR0 DMATX
    __I2C_TXDMA_Enable(I2Cx);

    if(I2Cx == I2C0)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x30)                          // Data NACK
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_STO_1(I2Cx);
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x38)                          // Arbitration lost
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH1A.W & (DMA_CH1A_CH1_TC2F_mask_w | DMA_CH1A_CH1_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH1A_CH1_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }
    else if (I2Cx == I2C1)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x30)                          // Data NACK
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH3A.W &= ~DMA_CH3A_CH3_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_STO_1(I2Cx);
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x38)                          // Arbitration lost
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH3A.W & (DMA_CH3A_CH3_TC2F_mask_w | DMA_CH3A_CH3_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH3A.W & DMA_CH3A_CH3_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }

    lSendDataLength = Size;                                 // Real TX Data Length

    while(__I2C_GetEventCode(I2Cx) != 0xF8);                // Wait Bus Stop

    *pRealTranSize = lSendDataLength;                       // Save Real Receive Data Length

    return SMP_OK;
}

/**
 ******************************************************************************
 *
 * @brief  Receive in master mode an amount of data in non-blocking mode with Interrupt
 * @param[in]  I2Cx: Pointer to a I2C_Struct structure that contains
 *                   the configuration information for the specified I2C.
 * @param[in]  DevAddress: Target device address
 * @param[in]  pData: Pointer to data buffer
 * @param[in]  Size: Amount of data to be sent
 * @param[out] pRealTranSize: Real Receive Data Length
 * @retval SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_I2C_Master_Receive_withDMA_Polling(I2C_Struct *I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint16_t *pRealTranSize)
{
    uint8_t lEVENTtemp;
//    uint16_t lSendDataLength;

    if((I2Cx->STA.W & I2C_STA_BUSYF_mask_w) != 0)
        return SMP_BUSY;

    // DMA RX Config Data Source and Length
    if(I2Cx == I2C0)
    {
        DMA->CH2A.W &= ~DMA_CH2A_CH2_EN_mask_w;
        __ISB();
        DMA->CH2A.W |= DMA_CH2A_CH2_EN_mask_w;

        DMA->CH2NUM.W = Size;
        DMA->CH2DSA.W = (uint32_t)pData;
        DMA->CH2A.W |= DMA_CH2A_CH2_REQ_enable_w;
    }
    else if(I2Cx == I2C1)
    {
        DMA->CH4A.W &= ~DMA_CH4A_CH4_EN_mask_w;
        __ISB();
        DMA->CH4A.W |= DMA_CH4A_CH4_EN_mask_w;

        DMA->CH4NUM.W = Size;
        DMA->CH4DSA.W = (uint32_t)pData;
        DMA->CH4A.W |= DMA_CH4A_CH4_REQ_enable_w;
    }
    else
        return SMP_ERROR;

    // Output BUS START
    __I2C_STA_1(I2Cx);
    __I2C_WaitEventFlag(I2Cx);
    __I2C_STA_0(I2Cx);
    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    if(lEVENTtemp != 0x08)
    {
        __I2C_ClearEventFlag(I2Cx);
        return SMP_ERROR;
    }

    // Output Device Address
    __I2C_SendSBUF(I2Cx, (((uint8_t)DevAddress) | 0x01));
    __I2C_ClearEventFlag(I2Cx);
    __I2C_WaitEventFlag(I2Cx);

    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    switch(lEVENTtemp){
        case 0x00 : // Bus Error
                    *pRealTranSize = 0;
                    __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                    __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x40 : // SLA+R has been transmitted  ACK has been received.
                    break;

        case 0x48 : // Device Address Not ACK.
                    *pRealTranSize = 0;
                    __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                    __I2C_STO_1(I2Cx);
                    __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x38 : // Arbitration lost
                    __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
        case 0x10 : // Repeat Start
                    *pRealTranSize = 0;
                     __I2C_ClearEventFlag(I2Cx);
                    return SMP_ERROR;

        case 0x68 : // Arbitration lost and Address match, Slave Receive Mode.
        case 0x78 : // Arbitration lost and Address match, Slave Receive General Call Mode.
        case 0xB0 : // Arbitration lost and Address match, Slave Transmitter Mode.
                    __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
        default :
                    *pRealTranSize = 0;
                    return SMP_ERROR;
    }

    __I2C_Set_STA_STO_AA_001(I2Cx); //Set AA bit is "1"

    // Set Last Data Byte retrun NACK
    __I2C_PreSet_STA_STO_AA_010(I2Cx);

    // Enable I2C CR0 DMARX
    __I2C_RXDMA_Enable(I2Cx);

    if(I2Cx == I2C0)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0xF8)                          // Bus STOP.
                break;

            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH2A.W & (DMA_CH2A_CH2_TC2F_mask_w | DMA_CH2A_CH2_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH2A_CH2_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }
    else if (I2Cx == I2C1)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0xF8)                          // Bus STOP
                break;

            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH4A.W & (DMA_CH4A_CH4_TC2F_mask_w | DMA_CH2A_CH2_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH2A_CH2_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }

    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    if(lEVENTtemp == 0x58)      // Set Last Data NACK
    {
        __I2C_STO_1(I2Cx);
        __I2C_ClearEventFlag(I2Cx);
        __I2C_WaitSTOClear(I2Cx);   // I2Cx IDLE State
    }

    return SMP_OK;
}

/**
 ******************************************************************************
 *
 * @brief       Receive in slave mode an amount of data in non-blocking mode with Interrupt
 * @param[in]   I2Cx: Pointer to a I2C_Struct structure that contains
 *               the configuration information for the specified I2C.
 * @param[in]   pData: Pointer to data buffer
 * @param[in]   Size: Amount of data to be sent
 * @param[out]  MatchAddress :
 * @param[out]  pRealTranSize :
 * @retval      SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_I2C_Slave_Receive_withDMA_Polling(I2C_Struct *I2Cx, uint8_t *pData, uint16_t Size, uint16_t *MatchAddress, uint16_t *pRealTranSize)
{
    uint8_t lEVENTtemp;
    //uint8_t lMatchAddress;

    if((I2Cx->STA.W & I2C_STA_BUSYF_mask_w) != 0)
        return SMP_BUSY;

    // DMA RX Config Data Source and Length
    if(I2Cx == I2C0)
    {
        DMA->CH2A.W &= ~DMA_CH2A_CH2_EN_mask_w;
        __ISB();
        DMA->CH2A.W |= DMA_CH2A_CH2_EN_mask_w;

        DMA->CH2NUM.W = Size;
        DMA->CH2DSA.W = (uint32_t)pData;
        DMA->CH2A.W |= DMA_CH2A_CH2_REQ_enable_w;
    }
    else if(I2Cx == I2C1)
    {
        DMA->CH4A.W &= ~DMA_CH4A_CH4_EN_mask_w;
        __ISB();
        DMA->CH4A.W |= DMA_CH4A_CH4_EN_mask_w;

        DMA->CH4NUM.W = Size;
        DMA->CH4DSA.W = (uint32_t)pData;
        DMA->CH4A.W |= DMA_CH4A_CH4_REQ_enable_w;
    }
    else
        return SMP_ERROR;

    // Enable Address Detect
    I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), ENABLE);
    __I2C_Set_STA_STO_AA_001(I2Cx); //Set AA bit is "1"

    // Wait H/W set EVENTF Flag, from Address Match.
    while(__I2C_GetEventFlag(I2Cx) == 0);

    // Check EVENT match Slave Receive Mode.
    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    if((lEVENTtemp != 0x60) && (lEVENTtemp != 0x68) && (lEVENTtemp != 0x70) && (lEVENTtemp != 0x78))
        return SMP_ERROR;

    if((lEVENTtemp == 0x68) || (lEVENTtemp != 0x78))
        __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));

    // Save Match Address
    *MatchAddress = (uint16_t)__I2C_ReadRxSBUF(I2Cx);

    // Set Last Data Byte retrun NACK
    __I2C_PreSet_STA_STO_AA_000(I2Cx);

    // Enable I2C CR0 DMARX
    __I2C_RXDMA_Enable(I2Cx);

    if(I2Cx == I2C0)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0xA0)                          // Bus STOP and Buffer lave
            {
                *pRealTranSize = (uint16_t)DMA->CH2CNT.W;   // Save Real Receive Data Length
                DMA->CH2A.W &= ~DMA_CH2A_CH2_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                break;
            }
        }while((DMA->CH2A.W & (DMA_CH2A_CH2_TC2F_mask_w | DMA_CH2A_CH2_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH2A_CH2_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }
    else if (I2Cx == I2C1)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0xA0)                          // Bus STOP and Buffer lave
            {
                *pRealTranSize = (uint16_t)DMA->CH4CNT.W;   // Save Real Receive Data Length
                DMA->CH4A.W &= ~DMA_CH4A_CH4_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                break;
            }
        }while((DMA->CH4A.W & (DMA_CH4A_CH4_TC2F_mask_w | DMA_CH2A_CH2_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH2A_CH2_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }

    *pRealTranSize = Size;                                  // Save Real Receive Data Length

    I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
    return SMP_OK;
}

/**
 ******************************************************************************
 *
 * @brief  Transmit in slave mode an amount of data in non-blocking mode with Interrupt
 * @param[in]   I2Cx: Pointer to a I2C_Struct structure that contains
 *              the configuration information for the specified I2C.
 * @param[in]   pData: Pointer to data buffer
 * @param[in]   Size: Amount of data to be sent
 * @param[out]  MatchAddress :
 * @param[out]  pRealTranSize :
 * @retval SMP status
 *
 ******************************************************************************
 */
SMP_StatusTypeDef SMP_I2C_Slave_Transmit_withDMA_Polling(I2C_Struct *I2Cx, uint8_t *pData, uint16_t Size, uint16_t *MatchAddress, uint16_t *pRealTranSize)
{
    uint8_t lEVENTtemp;
    uint16_t lSendDataLength;

    if((I2Cx->STA.W & I2C_STA_BUSYF_mask_w) != 0)
        return SMP_BUSY;

    // DMA TX Config Data Source and Length
    if(I2Cx == I2C0)
    {
        DMA->CH1A.W &= ~DMA_CH1A_CH1_EN_mask_w;
        __ISB();
        DMA->CH1A.W |= DMA_CH1A_CH1_EN_mask_w;

        DMA->CH1NUM.W = Size;
        DMA->CH1SSA.W = (uint32_t)pData;
        DMA->CH1A.W |= DMA_CH1A_CH1_REQ_enable_w;
    }
    else if(I2Cx == I2C1)
    {
        DMA->CH3A.W &= ~DMA_CH3A_CH3_EN_mask_w;
        __ISB();
        DMA->CH3A.W |= DMA_CH3A_CH3_EN_mask_w;

        DMA->CH3NUM.W = Size;
        DMA->CH3SSA.W = (uint32_t)pData;
        DMA->CH3A.W |= DMA_CH3A_CH3_REQ_enable_w;
    }
    else
        return SMP_ERROR;

    // Enable Address Detect
    I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_1 | I2C_SADR_2), ENABLE);
    __I2C_Set_STA_STO_AA_001(I2Cx); //Set AA bit is "1"

    // Wait H/W set EVENTF Flag, from Address Match.
    while(__I2C_GetEventFlag(I2Cx) == 0);

    // Check EVENT match Slave Receive Mode.
    lEVENTtemp = __I2C_GetEventCode(I2Cx);
    if((lEVENTtemp != 0xA8) && (lEVENTtemp != 0xB0))
        return SMP_ERROR;

    if(lEVENTtemp == 0xB0)
        __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));

    // Save Match Address
    *MatchAddress = (uint16_t)__I2C_ReadRxSBUF(I2Cx);

    // Set Last Data Byte retrun NACK
    __I2C_PreSet_STA_STO_AA_000(I2Cx);

    // Enable I2C CR0 DMATX
    __I2C_TXDMA_Enable(I2Cx);

    if(I2Cx == I2C0)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x38)                          // Arbitration lost
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0xC0)      // Data NACK
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
                __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH1A.W & (DMA_CH1A_CH1_TC2F_mask_w | DMA_CH1A_CH1_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH1A.W & DMA_CH1A_CH1_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }
    else if (I2Cx == I2C1)
    {
        do{
            lEVENTtemp = __I2C_GetEventCode(I2Cx);
            if(lEVENTtemp == 0x00)                          // Bus Error
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_BERRF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x10)                          // Repeat Start
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0x38)                          // Arbitration lost
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH1A.W &= ~DMA_CH1A_CH1_REQ_mask_w;
                __I2C_ClearFlag(I2Cx, (I2C_STA_ALOSF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
            if(lEVENTtemp == 0xC0)                          // Data NACK
            {
                *pRealTranSize = (uint16_t)DMA->CH1CNT.W;   // Save Real Receive Data Length
                DMA->CH3A.W &= ~DMA_CH3A_CH3_REQ_mask_w;
                I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
                __I2C_ClearFlag(I2Cx, (I2C_STA_NACKF_mask_w | I2C_STA_ERRF_mask_w));
                __I2C_ClearEventFlag(I2Cx);
                return SMP_ERROR;
            }
        }while((DMA->CH3A.W & (DMA_CH3A_CH3_TC2F_mask_w | DMA_CH3A_CH3_ERR2F_mask_w)) == 0);    // Buffer Full
        if((DMA->CH3A.W & DMA_CH3A_CH3_ERR2F_mask_w) != 0)
            return SMP_ERROR;
    }

    lSendDataLength = Size;                                  // Save Real Receive Data Length

    do{
        __I2C_SendSBUF(I2Cx, 0xFF);
        __I2C_WaitEventFlag(I2Cx);
        __I2C_ClearEventFlag(I2Cx);
        
        lEVENTtemp = __I2C_GetEventCode(I2Cx);
        lSendDataLength ++;

        if(lEVENTtemp == 0xC0)
            break;
    }while(1);

    while(__I2C_GetEventCode(I2Cx) != 0xF8);                // Wait Bus Stop

    *pRealTranSize = lSendDataLength;                       // Save Real Receive Data Length

    I2C_SlaveAddressDetect_Cmd(I2Cx, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), DISABLE);
    return SMP_OK;
}


