Newer
Older
mbed-os / targets / TARGET_TOSHIBA / TARGET_TMPM4NR / Periph_driver / src / txz_i2c_api.c
@Jay Sridharan Jay Sridharan on 31 Dec 2022 54 KB Merge upstream changes into mbed-ce (#117)
/**
 *******************************************************************************
 * @file    i2c_b.c
 * @brief   This file provides API functions for I2C Class.
 * @version V1.0.0
 *
 * DO NOT USE THIS SOFTWARE WITHOUT THE SOFTWARE LICENSE AGREEMENT.
 *
 * Copyright(C) TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2021
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************
 */
#ifdef __cplusplus
extern "C" {
#endif

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

#if defined(__BSP_I2C_H)

/**
 *  @addtogroup Example
 *  @{
 */

/**
 *  @addtogroup UTILITIES
 *  @{
 */
/*------------------------------------------------------------------------------*/
/*  Macro Function                                                              */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_macro
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_macro */

/*------------------------------------------------------------------------------*/
/*  Configuration                                                               */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */

/**
 *  @name  Parameter Result
 *  @brief Whether the parameter is specified or not.
 *  @{
 */
#define I2C_PARAM_OK              ((int32_t)1)              /*!< Parameter is valid(specified).         */
#define I2C_PARAM_NG              ((int32_t)0)              /*!< Parameter is invalid(not specified).   */
/**
 *  @}
 */ /* End of name Parameter Result */

/**
 *  @name  timeout
 *  @brief This timeouts are not based on accurate values, this just guarantee that
           the application will not remain stuck if the I2C communication is corrupted.
 *  @{
 */
#define I2C_TIMEOUT     (100000)    /*>! fail safe. */

/**
 *  @}
 */ /* End of name timeout */

#define I2CxSR_AL               ((uint32_t)0x00000008)     /*!< AL                      */
/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Macro Definition                                                            */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */
#define I2C_CH0                     (0)         /*!< I2C Channel 0.            */
#define I2C_CH1                     (1)         /*!< I2C Channel 1.            */
#define I2C_CH2                     (2)         /*!< I2C Channel 2.            */
#define I2C_CH3                     (3)         /*!< I2C Channel 3.            */
#define I2C_CH4                     (4)         /*!< I2C Channel 3.            */
#define I2C_CH_NUM                  (5)         /*!< Number of I2C Channel.    */

/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Enumerated Type Definition                                                  */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */
/*----------------------------------*/
/**
 * @brief  Transfer State.
*/
/*----------------------------------*/
enum {
    I2C_TRANSFER_STATE_IDLE = 0U,   /*!< Idle.                      */
    I2C_TRANSFER_STATE_BUSY         /*!< Busy.                      */
} TransferState;

/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Structure Definition                                                        */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_typedef
 *  @{
 */

/*----------------------------------*/
/**
 * @brief  For IRQn_Type number definition.
*/
/*----------------------------------*/
typedef struct {
    IRQn_Type i2c;
    IRQn_Type al;
    IRQn_Type bf;
    IRQn_Type na;
} i2c_irq_t;

/**
 *  @}
 */ /* End of group UTILITIES_Private_typedef */

/*------------------------------------------------------------------------------*/
/*  Private Member                                                              */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_variables
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_variables */

/*------------------------------------------------------------------------------*/
/*  Const Table                                                                 */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_const
 *  @{
 */
/*----------------------------------*/
/**
 * @brief  Channel 0 IRQn_Type number table.
*/
/*----------------------------------*/
static const i2c_irq_t I2C_CH0_IRQN_TBL[1] = {
    { INTI2C0NST_IRQn, INTI2C0ATX_IRQn, INTI2C0BRX_IRQn, INTI2C0NA_IRQn}
};

/*----------------------------------*/
/**
 * @brief  Channel 1 IRQn_Type number table.
*/
/*----------------------------------*/
static const i2c_irq_t I2C_CH1_IRQN_TBL[1] = {
    { INTI2C1NST_IRQn, INTI2C1ATX_IRQn, INTI2C1BRX_IRQn, INTI2C1NA_IRQn }
};

/*----------------------------------*/
/**
 * @brief  Channel 2 IRQn_Type number table.
*/
/*----------------------------------*/
static const i2c_irq_t I2C_CH2_IRQN_TBL[1] = {
    { INTI2C2NST_IRQn, INTI2C2ATX_IRQn, INTI2C2BRX_IRQn, INTI2C2NA_IRQn}
};

/*----------------------------------*/
/**
 * @brief  Channel 3 IRQn_Type number table.
*/
/*----------------------------------*/
static const i2c_irq_t I2C_CH3_IRQN_TBL[1] = {
    {INTI2C3NST_IRQn, INTI2C3ATX_IRQn, INTI2C3BRX_IRQn, INTI2C3NA_IRQn}
};

/*----------------------------------*/
/**
 * @brief  Channel 4 IRQn_Type number table.
*/
/*----------------------------------*/
static const i2c_irq_t I2C_CH4_IRQN_TBL[1] = {
    { INTI2C4NST_IRQn, INTI2C4ATX_IRQn, INTI2C4BRX_IRQn, INTI2C4NA_IRQn}
};
/**
 *  @}
 */ /* End of group UTILITIES_Private_const */

/*------------------------------------------------------------------------------*/
/*  Private Function                                                            */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_functions
 *  @{
 */
#ifdef DEBUG
__STATIC_INLINE int32_t check_param_irqn(uint32_t irqn);
__STATIC_INLINE int32_t check_param_address(int32_t address);
#endif
__STATIC_INLINE void enable_irq(uint32_t irqn);
__STATIC_INLINE void disable_irq(uint32_t irqn);
__STATIC_INLINE void clear_irq(uint32_t irqn);
__STATIC_INLINE void set_port_ch0(i2c_port_t sda, i2c_port_t scl);
__STATIC_INLINE void set_port_ch1(i2c_port_t sda, i2c_port_t scl);
__STATIC_INLINE void set_port_ch2(i2c_port_t sda, i2c_port_t scl);
__STATIC_INLINE void set_port_ch3(i2c_port_t sda, i2c_port_t scl);
__STATIC_INLINE void set_port_ch4(i2c_port_t sda, i2c_port_t scl);
__STATIC_INLINE void reset_asynch(_i2c_t *p_obj);
__STATIC_INLINE int32_t wait_status(_i2c_t *p_obj);
static void i2c_irq_handler(_i2c_t *p_obj);
static void i2c_slave_irq_handler(_i2c_t *p_obj);

#ifdef DEBUG
/*--------------------------------------------------*/
/**
  * @brief  Compare the IRQn's parameter.
  * @param  irqn         :I2C IRQn List.
  * @retval I2C_PARAM_OK :Available.
  * @retval I2C_PARAM_NG :Not Available.
  * @note   -.
  */
/*--------------------------------------------------*/
__STATIC_INLINE int32_t check_param_irqn(uint32_t irqn)
{
    int32_t result = I2C_PARAM_NG;

    if (irqn == (uint32_t)&I2C_CH0_IRQN_TBL) {
        result = I2C_PARAM_OK;
    }
    if (irqn == (uint32_t)&I2C_CH1_IRQN_TBL) {
        result = I2C_PARAM_OK;
    }
    if (irqn == (uint32_t)&I2C_CH2_IRQN_TBL) {
        result = I2C_PARAM_OK;
    }
    if (irqn == (uint32_t)&I2C_CH3_IRQN_TBL) {
        result = I2C_PARAM_OK;
    }
    if (irqn == (uint32_t)&I2C_CH4_IRQN_TBL) {
        result = I2C_PARAM_OK;
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief  Compare the Slave address's parameter.
  * @param  address      :Address.
  * @retval I2C_PARAM_OK :Available.
  * @retval I2C_PARAM_NG :Not Available.
  * @note   Here, 10bit address has not supported.
  */
/*--------------------------------------------------*/
__STATIC_INLINE int32_t check_param_address(int32_t address)
{
    int32_t result = I2C_PARAM_NG;

    if ((address >= 0) && (address <= 255)) {
        result = I2C_PARAM_OK;
    }
    return (result);
}
#endif

/*--------------------------------------------------*/
/**
  * @brief     Enable I2C IRQ
  * @param     irqn     :I2C IRQn List.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void enable_irq(uint32_t irqn)
{
    i2c_irq_t *p_irqn = (i2c_irq_t *)irqn;
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(check_param_irqn(irqn));
#endif /* #ifdef DEBUG */
    NVIC_EnableIRQ(p_irqn->i2c);
}

/*--------------------------------------------------*/
/**
  * @brief     Disable I2C IRQ
  * @param     irqn     :I2C IRQn List.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void disable_irq(uint32_t irqn)
{
    i2c_irq_t *p_irqn = (i2c_irq_t *)irqn;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(check_param_irqn(irqn));
#endif /* #ifdef DEBUG */
    NVIC_DisableIRQ(p_irqn->i2c);
    NVIC_DisableIRQ(p_irqn->al);
    NVIC_DisableIRQ(p_irqn->bf);
    NVIC_DisableIRQ(p_irqn->na);
}

/*--------------------------------------------------*/
/**
  * @brief     ClearPending I2C IRQ
  * @param     irqn     :I2C IRQn List.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void clear_irq(uint32_t irqn)
{
    i2c_irq_t *p_irqn = (i2c_irq_t *)irqn;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(check_param_irqn(irqn));
#endif /* #ifdef DEBUG */
    NVIC_ClearPendingIRQ(p_irqn->i2c);
    NVIC_ClearPendingIRQ(p_irqn->al);
    NVIC_ClearPendingIRQ(p_irqn->bf);
    NVIC_ClearPendingIRQ(p_irqn->na);
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Port Setting (PG2, PG3)
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void set_port_ch0(i2c_port_t sda, i2c_port_t scl)
{
    if ((sda == I2C_PORT_PG2) && (scl == I2C_PORT_PG3)) {
        /* Port G  */

        /* SCL */
        TSB_PG_IE_PG3IE   = 0;    /* Input       :Disable */
        TSB_PG_CR_PG3C    = 0;    /* Output      :Disable */
        TSB_PG_OD_PG3OD   = 1;    /* OD Control  :Open Drain */
        TSB_PG_PUP_PG3UP  = 0;    /* Pull-up     :Disable */
        TSB_PG_PDN_PG3DN  = 0;    /* Pull-down   :Disable */
        TSB_PG_DATA_PG3   = 0;    /* Data        :0       */
        TSB_PG_FR7_PG3F7  = 1;    /* Function    :I2C0SCL */
        TSB_PG_IE_PG3IE   = 1;    /* Input       :Enable  */
        TSB_PG_CR_PG3C    = 1;    /* Output      :Enable  */

        /* SDA */
        TSB_PG_IE_PG2IE   = 0;    /* Input      :Disable  */
        TSB_PG_CR_PG2C    = 0;    /* Output     :Disable  */
        TSB_PG_OD_PG2OD   = 1;    /* OD Control :Open Drain */
        TSB_PG_PUP_PG2UP  = 0;    /* Pull-up    :Disable  */
        TSB_PG_PDN_PG2DN  = 0;    /* Pull-down  :Disable  */
        TSB_PG_DATA_PG2   = 0;    /* Data       :0        */
        TSB_PG_FR7_PG2F7  = 1;    /* Function   :I2C0SDA  */
        TSB_PG_IE_PG2IE   = 1;    /* Input      :Enable   */
        TSB_PG_CR_PG2C    = 1;    /* Output     :Enable   */
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Port Setting (PF2, PF3)
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void set_port_ch1(i2c_port_t sda, i2c_port_t scl)
{
    if ((sda == I2C_PORT_PF2) && (scl == I2C_PORT_PF3)) {
        /* Port F  */

        /* SCL */
        TSB_PF_IE_PF3IE   = 0;    /* Input       :Disable */
        TSB_PF_CR_PF3C    = 0;    /* Output      :Disable */
        TSB_PF_OD_PF3OD   = 1;    /* OD Control  :Open Drain */
        TSB_PF_PUP_PF3UP  = 0;    /* Pull-up     :Disable */
        TSB_PF_PDN_PF3DN  = 0;    /* Pull-down   :Disable */
        TSB_PF_DATA_PF3   = 0;    /* Data        :0       */
        TSB_PF_FR7_PF3F7  = 1;    /* Function    :I2C0SCL */
        TSB_PF_IE_PF3IE   = 1;    /* Input       :Enable  */
        TSB_PF_CR_PF3C    = 1;    /* Output      :Enable  */

        /* SDA */
        TSB_PF_IE_PF2IE   = 0;    /* Input      :Disable  */
        TSB_PF_CR_PF2C    = 0;    /* Output     :Disable  */
        TSB_PF_OD_PF2OD   = 1;    /* OD Control :Open Drain */
        TSB_PF_PUP_PF2UP  = 0;    /* Pull-up    :Disable  */
        TSB_PF_PDN_PF2DN  = 0;    /* Pull-down  :Disable  */
        TSB_PF_DATA_PF2   = 0;    /* Data       :0        */
        TSB_PF_FR7_PF2F7  = 1;    /* Function   :I2C0SDA  */
        TSB_PF_IE_PF2IE   = 1;    /* Input      :Enable   */
        TSB_PF_CR_PF2C    = 1;    /* Output     :Enable   */
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Port Setting (PG4, PG5)
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void set_port_ch2(i2c_port_t sda, i2c_port_t scl)
{
    if ((sda == I2C_PORT_PG4) && (scl == I2C_PORT_PG5)) {
        /* Port G  */

        /* SCL */
        TSB_PG_IE_PG5IE   = 0;    /* Input       :Disable */
        TSB_PG_CR_PG5C    = 0;    /* Output      :Disable */
        TSB_PG_OD_PG5OD   = 1;    /* OD Control  :Open Drain */
        TSB_PG_PUP_PG5UP  = 0;    /* Pull-up     :Disable */
        TSB_PG_PDN_PG5DN  = 0;    /* Pull-down   :Disable */
        TSB_PG_DATA_PG5   = 0;    /* Data        :0       */
        TSB_PG_FR7_PG5F7  = 1;    /* Function    :I2C0SCL */
        TSB_PG_IE_PG5IE   = 1;    /* Input       :Enable  */
        TSB_PG_CR_PG5C    = 1;    /* Output      :Enable  */

        /* SDA */
        TSB_PG_IE_PG4IE   = 0;    /* Input      :Disable  */
        TSB_PG_CR_PG4C    = 0;    /* Output     :Disable  */
        TSB_PG_OD_PG4OD   = 1;    /* OD Control :Open Drain */
        TSB_PG_PUP_PG4UP  = 0;    /* Pull-up    :Disable  */
        TSB_PG_PDN_PG4DN  = 0;    /* Pull-down  :Disable  */
        TSB_PG_DATA_PG4   = 0;    /* Data       :0        */
        TSB_PG_FR7_PG4F7  = 1;    /* Function   :I2C0SDA  */
        TSB_PG_IE_PG4IE   = 1;    /* Input      :Enable   */
        TSB_PG_CR_PG4C    = 1;    /* Output     :Enable   */
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Port Setting (PM0, PM1)
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void set_port_ch3(i2c_port_t sda, i2c_port_t scl)
{
    if ((sda == I2C_PORT_PJ6) && (scl == I2C_PORT_PJ7)) {
        /* Port M  */

        /* SCL */
        TSB_PJ_IE_PJ6IE   = 0;    /* Input       :Disable */
        TSB_PJ_CR_PJ6C    = 0;    /* Output      :Disable */
        TSB_PJ_OD_PJ6OD   = 1;    /* OD Control  :Open Drain */
        TSB_PJ_PUP_PJ6UP  = 0;    /* Pull-up     :Disable */
        TSB_PJ_PDN_PJ6DN  = 0;    /* Pull-down   :Disable */
        TSB_PJ_DATA_PJ6   = 0;    /* Data        :0       */
        TSB_PJ_FR7_PJ6F7  = 1;    /* Function    :I2C3SCL */
        TSB_PJ_IE_PJ6IE   = 1;    /* Input       :Enable  */
        TSB_PJ_CR_PJ6C    = 1;    /* Output      :Enable  */

        /* SDA */
        TSB_PJ_IE_PJ7IE   = 0;    /* Input      :Disable  */
        TSB_PJ_CR_PJ7C    = 0;    /* Output     :Disable  */
        TSB_PJ_OD_PJ7OD   = 1;    /* OD Control :Open Drain */
        TSB_PJ_PUP_PJ7UP  = 0;    /* Pull-up    :Disable  */
        TSB_PJ_PDN_PJ7DN  = 0;    /* Pull-down  :Disable  */
        TSB_PJ_DATA_PJ7   = 0;    /* Data       :0        */
        TSB_PJ_FR7_PJ7F7  = 1;    /* Function   :I2C3SDA  */
        TSB_PJ_IE_PJ7IE   = 1;    /* Input      :Enable   */
        TSB_PJ_CR_PJ7C    = 1;    /* Output     :Enable   */
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Port Setting (PM6, PM7)
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void set_port_ch4(i2c_port_t sda, i2c_port_t scl)
{
    if ((sda == I2C_PORT_PJ2) && (scl == I2C_PORT_PJ3)) {
        /* Port M  */

        /* SCL */
        TSB_PJ_IE_PJ2IE   = 0;    /* Input       :Disable */
        TSB_PJ_CR_PJ2C    = 0;    /* Output      :Disable */
        TSB_PJ_OD_PJ2OD   = 1;    /* OD Control  :Open Drain */
        TSB_PJ_PUP_PJ2UP  = 0;    /* Pull-up     :Disable */
        TSB_PJ_PDN_PJ2DN  = 0;    /* Pull-down   :Disable */
        TSB_PJ_DATA_PJ2   = 0;    /* Data        :0       */
        TSB_PJ_FR7_PJ2F7  = 1;    /* Function    :I2C3SCL */
        TSB_PJ_IE_PJ2IE   = 1;    /* Input       :Enable  */
        TSB_PJ_CR_PJ2C    = 1;    /* Output      :Enable  */

        /* SDA */
        TSB_PJ_IE_PJ3IE   = 0;    /* Input      :Disable  */
        TSB_PJ_CR_PJ3C    = 0;    /* Output     :Disable  */
        TSB_PJ_OD_PJ3OD   = 1;    /* OD Control :Open Drain */
        TSB_PJ_PUP_PJ3UP  = 0;    /* Pull-up    :Disable  */
        TSB_PJ_PDN_PJ3DN  = 0;    /* Pull-down  :Disable  */
        TSB_PJ_DATA_PJ3   = 0;    /* Data       :0        */
        TSB_PJ_FR7_PJ3F7  = 1;    /* Function   :I2C3SDA  */
        TSB_PJ_IE_PJ3IE   = 1;    /* Input      :Enable   */
        TSB_PJ_CR_PJ3C    = 1;    /* Output     :Enable   */
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Setting
  * @param     ch       :I2C Channel.
  * @param     p_irqn   :Destination Address of a I2C IRQn List.
  * @retval    non-zero :Instance Address.
  * @retval    zero     :Channel not supported.
  * @note      -
  */
/*--------------------------------------------------*/
uint32_t set_i2c(uint8_t ch, uint32_t *p_irqn)
{
    uint32_t instance = 0;

    switch (ch) {
        case I2C_CH0:
            instance = (uint32_t)TSB_I2C0;
            *p_irqn = (uint32_t)&I2C_CH0_IRQN_TBL;
            break;

        case I2C_CH1:
            instance = (uint32_t)TSB_I2C1;
            *p_irqn = (uint32_t)&I2C_CH1_IRQN_TBL;
            break;

        case I2C_CH2:
            instance = (uint32_t)TSB_I2C2;
            *p_irqn = (uint32_t)&I2C_CH2_IRQN_TBL;
            break;

        case I2C_CH3:
            instance = (uint32_t)TSB_I2C3;
            *p_irqn = (uint32_t)&I2C_CH3_IRQN_TBL;
            break;

        case I2C_CH4:
            instance = (uint32_t)TSB_I2C4;
            *p_irqn = (uint32_t)&I2C_CH4_IRQN_TBL;
            break;

        default:
            break;
    }
    return (instance);
}

/*--------------------------------------------------*/
/**
  * @brief     Reset Asynch Transfer
  * @param     p_obj    :i2c object
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE void reset_asynch(_i2c_t *p_obj)
{
    disable_irq(p_obj->info.irqn);
    I2C_disable_interrupt(&p_obj->i2c);
}

__STATIC_INLINE int32_t I2C_status_arbitration(I2C_t *p_obj)
{
#ifdef DEBUG
    if ((p_obj != I2C_NULL) && (p_obj->p_instance != I2C_NULL)) {
        return ((p_obj->p_instance->SR & I2CxSR_AL) == I2CxSR_AL);
    }
    return (0);
#else
    return ((p_obj->p_instance->SR & I2CxSR_AL) == I2CxSR_AL);
#endif
}
/*--------------------------------------------------*/
/**
  * @brief     Waiting i2c status
  * @param     p_obj    :i2c object
  * @retval    0        :Success.
  * @retval    -1       :Failure.
  * @note      -
  */
/*--------------------------------------------------*/
__STATIC_INLINE int32_t wait_status(_i2c_t *p_obj)
{
    int32_t timeout;

    timeout = I2C_TIMEOUT;
    while (!I2C_int_status(&p_obj->i2c)) {
        if (I2C_status_arbitration(&p_obj->i2c)) {
            volatile uint32_t dummy = 0;
            dummy = I2C_read_data(&p_obj->i2c);
            (void)dummy;
            return (-5);
        }
        if ((timeout--) == 0) {
            return (-1);
        }
    }
    if (I2C_status_arbitration(&p_obj->i2c)) {
        volatile uint32_t dummy = 0;
        dummy = I2C_read_data(&p_obj->i2c);
        (void)dummy;
        return (-5);
    }
    return (0);
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Transfer handler
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      Called by i2c_irq_handler_asynch_t.
  */
/*--------------------------------------------------*/
static void i2c_irq_handler(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    I2C_clear_int_status(&p_obj->i2c);

    if ((!I2C_master(&p_obj->i2c)) || (p_obj->info.asynch.state != I2C_TRANSFER_STATE_BUSY)) {
        p_obj->info.asynch.event = I2C_EVENT_ERROR;
        p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
    } else {
        if (I2C_transmitter(&p_obj->i2c)) {
            int32_t start = I2C_restart(&p_obj->i2c);
            (void)start;

            if (!I2C_get_ack(&p_obj->i2c)) {
                if (p_obj->tx_buff.pos < p_obj->tx_buff.length) {
                    I2C_write_data(&p_obj->i2c, (uint32_t)p_obj->tx_buff.p_buffer[p_obj->tx_buff.pos++]);
                } else if (p_obj->rx_buff.length != 0) {
                    I2C_start_condition(&p_obj->i2c, (p_obj->info.asynch.address | 1U));
                } else {
                    if (p_obj->info.asynch.stop) {
                        I2C_stop_condition(&p_obj->i2c);
                    }
                    p_obj->info.asynch.event = I2C_EVENT_TRANSFER_COMPLETE;
                    p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
                }
            } else {
                if ((p_obj->tx_buff.pos < p_obj->tx_buff.length) || (p_obj->tx_buff.length == 0)) {
                    if (p_obj->tx_buff.pos == 0) {
                        p_obj->info.asynch.event = (I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE);
                        p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
                    } else {
                        p_obj->info.asynch.event = (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK);
                        p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
                    }
                } else if (p_obj->rx_buff.length != 0) {
                    I2C_start_condition(&p_obj->i2c, (p_obj->info.asynch.address | 1U));
                } else {
                    if (p_obj->info.asynch.stop) {
                        I2C_stop_condition(&p_obj->i2c);
                    }
                    p_obj->info.asynch.event = I2C_EVENT_TRANSFER_COMPLETE;
                    p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
                }
            }
        } else {
            int32_t start = I2C_restart(&p_obj->i2c);

            if (p_obj->rx_buff.pos < p_obj->rx_buff.length) {
                if (!start) {
                    p_obj->rx_buff.p_buffer[p_obj->rx_buff.pos++] = (uint8_t)I2C_read_data(&p_obj->i2c);
                }
            }
            if (p_obj->rx_buff.pos < p_obj->rx_buff.length) {
                I2C_set_ack(&p_obj->i2c, ((p_obj->rx_buff.pos < (p_obj->rx_buff.length - 1) ? 0 : 1)));
                I2C_write_data(&p_obj->i2c, 0);
            } else {
                if (p_obj->info.asynch.stop) {
                    I2C_stop_condition(&p_obj->i2c);
                }
                p_obj->info.asynch.event = I2C_EVENT_TRANSFER_COMPLETE;
                p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
            }
        }
    }
    if (p_obj->info.asynch.state == I2C_TRANSFER_STATE_IDLE) {
        reset_asynch(p_obj);
    }
}

/*--------------------------------------------------*/
/**
  * @brief     I2C Transfer handler
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      Called by i2c_slave_irq_handler_asynch_t.
  */
/*--------------------------------------------------*/
static void i2c_slave_irq_handler(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    I2C_clear_int_status(&p_obj->i2c);

    if ((I2C_master(&p_obj->i2c)) || (p_obj->info.asynch.state != I2C_TRANSFER_STATE_BUSY)) {
        p_obj->info.asynch.event = I2C_EVENT_ERROR;
        p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
    } else {
        int32_t start = I2C_slave_detected(&p_obj->i2c);
        if (start) {
            uint8_t sa = (uint8_t)I2C_read_data(&p_obj->i2c);
            (void)sa;
        }
        if (I2C_transmitter(&p_obj->i2c)) {
            if (!I2C_get_ack(&p_obj->i2c)) {
                if (p_obj->tx_buff.pos < p_obj->tx_buff.length) {
                    I2C_write_data(&p_obj->i2c, (uint32_t)p_obj->tx_buff.p_buffer[p_obj->tx_buff.pos++]);
                } else {
                    /* dummy, wait nack */
                    I2C_write_data(&p_obj->i2c, 0);
                }
            } else {
                /* error event not be set */
                p_obj->info.asynch.event = I2C_EVENT_TRANSFER_COMPLETE;
                p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
            }
        } else {
            if (p_obj->rx_buff.pos < p_obj->rx_buff.length) {
                if (!start) {
                    p_obj->rx_buff.p_buffer[p_obj->rx_buff.pos++] = (uint8_t)I2C_read_data(&p_obj->i2c);
                }
            }
            if (p_obj->rx_buff.pos < p_obj->rx_buff.length) {
                I2C_set_ack(&p_obj->i2c, ((p_obj->rx_buff.pos < (p_obj->rx_buff.length - 1) ? 0 : 1)));
                I2C_write_data(&p_obj->i2c, 0);
            } else {
                p_obj->info.asynch.event = I2C_EVENT_TRANSFER_COMPLETE;
                p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
            }
        }
    }
    if (p_obj->info.asynch.state == I2C_TRANSFER_STATE_IDLE) {
        reset_asynch(p_obj);
        I2C_slave_init(&p_obj->i2c);
    }
}

/*--------------------------------------------------*/
/**
  * @brief     Enable I2C IRQ
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void i2c_enable_irq(_i2c_t *p_obj)
{
    enable_irq(p_obj->info.irqn);
}

/*--------------------------------------------------*/
/**
  * @brief     Disable I2C IRQ
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void i2c_disable_irq(_i2c_t *p_obj)
{
    disable_irq(p_obj->info.irqn);
}

/**
 *  @}
 */ /* End of group UTILITIES_Private_functions */

/*------------------------------------------------------------------------------*/
/*  Public Function                                                             */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Exported_functions
 *  @{
 */

/*--------------------------------------------------*/
/**
  * @brief     Initialize the I2C Driver
  * @param     p_obj       :i2c object.
  * @param     sda         :SDA port.
  * @param     scl         :SCL port.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_init_t(_i2c_t *p_obj, i2c_port_t sda, i2c_port_t scl)
{
    TXZ_Result result = TXZ_ERROR;
    uint32_t instance = 0;
    uint32_t irqn = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    /* ch0 */
    if ((sda == I2C_PORT_PG2) && (scl == I2C_PORT_PG3)) {
        set_port_ch0(sda, scl);
        instance = set_i2c(I2C_CH0, &irqn);
    }
    /* ch1 */
    if ((sda == I2C_PORT_PF2) && (scl == I2C_PORT_PF3)) {
        set_port_ch1(sda, scl);
        instance = set_i2c(I2C_CH1, &irqn);
    }
    /* ch2 */
    if ((sda == I2C_PORT_PG4) && (scl == I2C_PORT_PG5)) {
        set_port_ch2(sda, scl);
        instance = set_i2c(I2C_CH2, &irqn);
    }
    /* ch3 */
    if ((sda == I2C_PORT_PJ6) && (scl == I2C_PORT_PJ7)) {
        set_port_ch3(sda, scl);
        instance = set_i2c(I2C_CH3, &irqn);
    }
    /* ch4 */
    if ((sda == I2C_PORT_PJ2) && (scl == I2C_PORT_PJ3)) {
        set_port_ch4(sda, scl);
        instance = set_i2c(I2C_CH3, &irqn);
    }

    if ((instance != 0) && (irqn != 0)) {
        disable_irq(irqn);
        clear_irq(irqn);

        /* Set irqn table */
        p_obj->info.irqn = irqn;

        /* Set instance */
        p_obj->i2c.p_instance = (TSB_I2C_TypeDef *)instance;

        /* I2C Reset */
        i2c_reset_t(p_obj);

        /* Set Frequency Default at 100KHz */
        if (i2c_frequency_t(p_obj, 100000) == TXZ_SUCCESS) {
            result = TXZ_SUCCESS;
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Reset I2C peripheral
  * @param     p_obj       :i2c object.
  * @retval    -
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
void i2c_reset_t(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    /* Software reset */
    I2C_reset(&p_obj->i2c);
}

/*--------------------------------------------------*/
/**
  * @brief     Configure the I2C frequency
  * @param     p_obj       :i2c object.
  * @param     hz          :frequency in Hz.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_frequency_t(_i2c_t *p_obj, int32_t hz)
{
    TXZ_Result result = TXZ_ERROR;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    if (I2C_port_high(&p_obj->i2c)) {
        uint32_t fval;

        SystemCoreClockUpdate();

        fval = I2C_get_clock_setting(&p_obj->i2c, (uint32_t)hz, SystemCoreClock, &p_obj->i2c.init.clock);
        if (fval != 0) {
            //I2C_init(&p_obj->i2c);
            p_obj->info.bus_free = 0;
            p_obj->info.start = 0;
            p_obj->info.asynch.address = 0;
            p_obj->info.asynch.stop = 0;
            p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
            p_obj->info.asynch.event = 0;
            p_obj->tx_buff.p_buffer = I2C_NULL;
            p_obj->tx_buff.length = 0;
            p_obj->tx_buff.pos = 0;
            p_obj->rx_buff.p_buffer = I2C_NULL;
            p_obj->rx_buff.length = 0;
            p_obj->rx_buff.pos = 0;
            result = TXZ_SUCCESS;
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Check bus free on the I2C bus.
  * @param     p_obj       :i2c object.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_check_bus_free_t(_i2c_t *p_obj)
{
    TXZ_Result result = TXZ_SUCCESS;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    p_obj->info.bus_free = 1;

    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Creates a start condition on the I2C bus.
  * @param     p_obj       :i2c object.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.(now, not use)
  * @note      Start condition is not generate yet, after this function returned.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_start_t(_i2c_t *p_obj)
{
    TXZ_Result result = TXZ_SUCCESS;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    p_obj->info.start = 1;

    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Creates a stop condition on the I2C bus.
  * @param     p_obj       :i2c object.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      Master and blocking function.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_stop_t(_i2c_t *p_obj)
{
    TXZ_Result result = TXZ_SUCCESS;
    int32_t timeout;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    I2C_stop_condition(&p_obj->i2c);
    p_obj->info.bus_free = 0;
    p_obj->info.start = 0;

    timeout = I2C_TIMEOUT;
    while (i2c_active_t(p_obj)) {
        if ((timeout--) == 0) {
            result = TXZ_ERROR;
            break;
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Blocking reading data
  * @param     p_obj       :i2c object.
  * @param     address     :Slave address(7-bit) and last bit is 0.
  * @param     p_data      :Address of Read data.
  * @param     length      :Number of the bytes to read.
  * @param     stop        :Stop to be generated after the transfer is done.
  * @retval    Number of read bytes.
  * @note      Master and blocking function.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_read_t(_i2c_t *p_obj, int32_t address, uint8_t *p_data, int32_t length, int32_t stop)
{
    int32_t result = 0;
    int32_t count = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_data));
    assert_param(check_param_address(address));
#endif /* #ifdef DEBUG */

    if (length > 0) {
        /* Start Condition */
        if (i2c_start_t(p_obj) == TXZ_SUCCESS) {
            /* no processing */
        }
        result = i2c_byte_write_t(p_obj, (int32_t)((uint32_t)address | 1U));
        if (result == I2C_ACK) {
            /* Read all bytes */
            while (count < length) {
                int32_t data = i2c_byte_read_t(p_obj, ((count < (length - 1)) ? 0 : 1));
                if (data < 0) {
                    result = data;
                    break;
                }
                p_data[count++] = (uint8_t)data;
            }
            result = count;
        } else if (result == I2C_ERROR_ARBITRATION) {
        } else if (result == (-2)) { //I2C_ERROR_BUS_BUSY
        } else {
            stop = 1;
            result = (-1) ;//I2C_ERROR_NO_SLAVE;
        }
        /* Stop Condition */
        if (stop) {
            if (i2c_stop_t(p_obj) == TXZ_SUCCESS) {
                /* no processing */
            }
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Blocking sending data
  * @param     p_obj       :i2c object.
  * @param     address     :Slave address(7-bit) and last bit is 0.
  * @param     p_data      :Destination address of Write data.
  * @param     length      :Number of the bytes to write.
  * @param     stop        :Stop to be generated after the transfer is done.
  * @retval    Number of write bytes.
  * @note      Master and blocking function.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_write_t(_i2c_t *p_obj, int32_t address, uint8_t *p_data, int32_t length, int32_t stop)
{
    int32_t result = 0;
    int32_t count = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_data));
    assert_param(check_param_address(address));
#endif /* #ifdef DEBUG */

    /* Start Condition */
    if (i2c_start_t(p_obj) == TXZ_SUCCESS) {
        /* no processing */
    }
    result = i2c_byte_write_t(p_obj, address);
    if (result == I2C_ACK) {
        /* Write all bytes */
        while (count < length) {
            int32_t data = i2c_byte_write_t(p_obj, (int32_t)p_data[count++]);
            if (data < I2C_ACK) {
                result = data;
                break;
            }
        }
        if (result >= 0) {
            result = count;
        }
    } else if (result == I2C_ERROR_ARBITRATION) {
    } else if (result == (-2)) { //I2C_ERROR_BUS_BUSY
    } else {
        stop = 1;
        result = (-1); //I2C_ERROR_NO_SLAVE;
    }
    /* Stop Condition */
    if (stop) {
        if (i2c_stop_t(p_obj) == TXZ_SUCCESS) {
            /* no processing */
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Read one byte
  * @param     p_obj       :i2c object.
  * @param     last        :last acknowledge.
  * @retval    The read byte (but -1 is timout error).
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_byte_read_t(_i2c_t *p_obj, int32_t last)
{
    int32_t result;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    I2C_clear_int_status(&p_obj->i2c);
    I2C_set_ack(&p_obj->i2c, last);
    I2C_write_data(&p_obj->i2c, 0);
    result = wait_status(p_obj);
    if (result < 0) {
        //    result = -1;
    } else {
        result = (int32_t)I2C_read_data(&p_obj->i2c);
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Write one byte
  * @param     p_obj     :i2c object.
  * @param     data      :Write data.
  * @retval    0         :NACK was received.
  * @retval    1         :ACK was received.
  * @retval    -1        :Timout error.
  * @note      Macro definition of return values is @ref I2C_ACK.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_byte_write_t(_i2c_t *p_obj, int32_t data)
{
    int32_t result;
    int32_t timeout;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    I2C_clear_int_status(&p_obj->i2c);
    if (p_obj->info.start == 1) {
        p_obj->info.start = 0;
        if (p_obj->info.bus_free == 1) {
            timeout = I2C_TIMEOUT;
            while (i2c_active_t(p_obj)) {
                if ((timeout--) == 0) {
                    p_obj->info.bus_free = 0;
                    return (-1);
                }
            }
        }
        /* Start Condition */
        I2C_start_condition(&p_obj->i2c, (uint32_t)data);
        if ((p_obj->info.bus_free == 1) && (!I2C_master(&p_obj->i2c))) {
            p_obj->i2c.p_instance->CR2 = (I2CxCR2_INIT | I2CxCR2_PIN_CLEAR);
            p_obj->info.bus_free = 0;
            if (I2C_status_arbitration(&p_obj->i2c)) {
                return (-5);
            }
            return (-2);
        }
    } else {
        I2C_write_data(&p_obj->i2c, (uint32_t)data);
    }
    p_obj->info.bus_free = 0;
    result = wait_status(p_obj);
    if (result < 0) {
        return (result);
    }
    if (!I2C_get_ack(&p_obj->i2c)) {
        result = 1;
    } else {
        result = 0;
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Attempts to determine if the I2C bus is already in use
  * @param     p_obj     :i2c object.
  * @retval    0         :Non-active.
  * @retval    1         :Active.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
uint8_t i2c_active_t(_i2c_t *p_obj)
{
    uint8_t result;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    if (I2C_status_busy(&p_obj->i2c)) {
        result = 1;
    } else {
        result = 0;
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Start I2C asynchronous transfer
  * @param     p_obj     :i2c object.
  * @param     p_tx      :Buffer of write data.
  * @param     tx_length :Length of write data.
  * @param     p_rx      :Buffer of read data.
  * @param     rx_length :Length of read data.
  * @param     address   :Slave address(7-bit) and last bit is 0.
  * @param     stop      :Stop to be generated after the transfer is done.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      Master and non-blocking function.
  * @note      Events of this function will be notified on i2c_irq_handler_asynch_t.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_transfer_asynch_t(_i2c_t *p_obj, uint8_t *p_tx, int32_t tx_length, uint8_t *p_rx, int32_t rx_length, int32_t address, int32_t stop)
{
    TXZ_Result result = TXZ_ERROR;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(check_param_address(address));
#endif /* #ifdef DEBUG */

    if (p_obj->info.asynch.state == I2C_TRANSFER_STATE_IDLE) {
        reset_asynch(p_obj);
        I2C_clear_int_status(&p_obj->i2c);
        clear_irq(p_obj->info.irqn);
        p_obj->info.asynch.address = (uint32_t)address;
        p_obj->info.asynch.event = 0;
        p_obj->info.asynch.stop = (uint32_t)stop;
        p_obj->tx_buff.p_buffer = p_tx;
        p_obj->tx_buff.length = (uint32_t)tx_length;
        p_obj->tx_buff.pos = 0;
        p_obj->rx_buff.p_buffer = p_rx;
        p_obj->rx_buff.length = (uint32_t)rx_length;
        p_obj->rx_buff.pos = 0;
        p_obj->info.asynch.state = I2C_TRANSFER_STATE_BUSY;
        I2C_enable_interrupt(&p_obj->i2c);
        if ((tx_length == 0) && (rx_length != 0)) {
            I2C_start_condition(&p_obj->i2c, (uint32_t)((uint32_t)address | 1U));
        } else {
            I2C_start_condition(&p_obj->i2c, (uint32_t)address);
        }
        p_obj->info.bus_free = 0;
        p_obj->info.start = 0;
        enable_irq(p_obj->info.irqn);
        result = TXZ_SUCCESS;
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     The asynchronous IRQ handler
  * @param     p_obj     :i2c object.
  * @retval    zero      :Transfer in progress.
  * @retval    non-zero  :Event information.
  * @note      Macro definition of return values is @ref I2C_Events.
  * @attention This function should be implement as INTI2Cx_IRQHandler.
  */
/*--------------------------------------------------*/
uint32_t i2c_irq_handler_asynch_t(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    i2c_irq_handler(p_obj);

    return (p_obj->info.asynch.event & I2C_EVENT_ALL);
}

/*--------------------------------------------------*/
/**
  * @brief     Abort asynchronous transfer
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      After error event occurred on i2c_irq_handler_asynch_t,
  * @note      call this function and clear error status.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
void i2c_abort_asynch_t(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    reset_asynch(p_obj);
    if (i2c_stop_t(p_obj) == TXZ_SUCCESS) {
        /* no processing */
    }
    p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
    i2c_reset_t(p_obj);
    I2C_init(&p_obj->i2c);
    clear_irq(p_obj->info.irqn);
}

/*--------------------------------------------------*/
/**
  * @brief     Configure I2C as slave or master.
  * @param     p_obj        :i2c object.
  * @param     enable_slave :Enable slave mode.
  * @retval    -
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
void i2c_slave_mode_t(_i2c_t *p_obj, int32_t enable_slave)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    disable_irq(p_obj->info.irqn);

    if (enable_slave) {
        I2C_slave_init(&p_obj->i2c);
    } else {
        /* Slave Disable Settings. */
        i2c_reset_t(p_obj);
        I2C_init(&p_obj->i2c);
    }
    p_obj->info.bus_free = 0;
    p_obj->info.start = 0;
    I2C_clear_int_status(&p_obj->i2c);
}

/*--------------------------------------------------*/
/**
  * @brief     Check to see if the I2C slave has been addressed.
  * @param     p_obj               :i2c object.
  * @retval    I2C_NO_DATA         :The slave has not been addressed.
  * @retval    I2C_READ_ADDRESSED  :Read addresses.
  * @retval    I2C_WRITE_GENERAL   :Write to all slaves(now, not support).
  * @retval    I2C_WRITE_ADDRESSED :Write addressed.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_slave_receive_t(_i2c_t *p_obj)
{
    int32_t result = I2C_NO_DATA;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    if (I2C_slave_detected(&p_obj->i2c)) {
        uint32_t sa = I2C_read_data(&p_obj->i2c);
        (void)sa;

        if (!I2C_transmitter(&p_obj->i2c)) {
            result = I2C_WRITE_ADDRESSED;
        } else {
            result = I2C_READ_ADDRESSED;
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Blocking reading data.
  * @param     p_obj     :i2c object.
  * @param     p_data    :Destination address of read data.
  * @param     length    :Number of bytes to read.
  * @retval    Number of read bytes.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_slave_read_t(_i2c_t *p_obj, uint8_t *p_data, int32_t length)
{
    int32_t count = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_data));
#endif /* #ifdef DEBUG */

    /* Read all bytes */
    while (count < length) {
        I2C_clear_int_status(&p_obj->i2c);
        I2C_set_ack(&p_obj->i2c, ((count < (length - 1)) ? 0 : 1));
        I2C_write_data(&p_obj->i2c, 0);
        if (wait_status(p_obj) < 0) {
            break;
        }
        if (I2C_slave_detected(&p_obj->i2c)) {
            return (count);
        }
        p_data[count++] = (uint8_t)I2C_read_data(&p_obj->i2c);
    }
    I2C_slave_init(&p_obj->i2c);
    return (count);
}

/*--------------------------------------------------*/
/**
  * @brief     Blocking sending data.
  * @param     p_obj     :i2c object.
  * @param     p_data    :Source address of write data.
  * @param     length    :Number of bytes to write.
  * @retval    Number of written bytes.
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
int32_t i2c_slave_write_t(_i2c_t *p_obj, uint8_t *p_data, int32_t length)
{
    int32_t count = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_data));
#endif /* #ifdef DEBUG */

    /* Write all bytes */
    while (count < length) {
        I2C_clear_int_status(&p_obj->i2c);
        I2C_write_data(&p_obj->i2c, (uint32_t)p_data[count++]);
        if (wait_status(p_obj) < 0) {
            break;
        }
        if (!I2C_get_ack(&p_obj->i2c)) {
            /* continue */
        } else {
            break;
        }
    }
    I2C_slave_init(&p_obj->i2c);
    return (count);
}

/*--------------------------------------------------*/
/**
  * @brief     Configure I2C slave address.
  * @param     p_obj     :i2c object.
  * @param     address   :Address to be set.
  * @retval    -
  * @note      -
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
void i2c_slave_address_t(_i2c_t *p_obj, uint32_t address)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(check_param_address((int32_t)address));
#endif /* #ifdef DEBUG */

    I2C_set_address(&p_obj->i2c, address);
}


/*--------------------------------------------------*/
/**
  * @brief     Start I2C asynchronous transfer
  * @param     p_obj     :i2c object.
  * @param     p_tx      :Buffer of write data.
  * @param     tx_length :Length of write data.
  * @param     p_rx      :Buffer of read data.
  * @param     rx_length :Length of read data.
  * @retval    TXZ_SUCCESS :Success.
  * @retval    TXZ_ERROR   :Failure.
  * @note      Slave and non-blocking function.
  * @note      Events of this function will be notified on i2c_slave_irq_handler_asynch_t.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
TXZ_Result i2c_slave_transfer_asynch_t(_i2c_t *p_obj, uint8_t *p_tx, int32_t tx_length, uint8_t *p_rx, int32_t rx_length)
{
    TXZ_Result result = TXZ_ERROR;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    if (p_obj->info.asynch.state == I2C_TRANSFER_STATE_IDLE) {
        if (((p_tx != I2C_NULL) && (tx_length > 0)) || ((p_rx != I2C_NULL) && (rx_length > 0))) {
            reset_asynch(p_obj);
            I2C_clear_int_status(&p_obj->i2c);
            clear_irq(p_obj->info.irqn);
            p_obj->info.asynch.address = 0;
            p_obj->info.asynch.event = 0;
            p_obj->info.asynch.stop = 0;
            p_obj->tx_buff.p_buffer = p_tx;
            p_obj->tx_buff.length = (uint32_t)tx_length;
            p_obj->tx_buff.pos = 0;
            p_obj->rx_buff.p_buffer = p_rx;
            p_obj->rx_buff.length = (uint32_t)rx_length;
            p_obj->rx_buff.pos = 0;
            p_obj->info.asynch.state = I2C_TRANSFER_STATE_BUSY;
            I2C_enable_interrupt(&p_obj->i2c);
            enable_irq(p_obj->info.irqn);
            result = TXZ_SUCCESS;
        }
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     The asynchronous IRQ handler
  * @param     p_obj     :i2c object.
  * @retval    zero      :Transfer in progress.
  * @retval    non-zero  :Event information.
  * @note      Macro definition of return values is @ref I2C_Events.
  * @attention This function should be implement as INTI2Cx_IRQHandler.
  */
/*--------------------------------------------------*/
uint32_t i2c_slave_irq_handler_asynch_t(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    i2c_slave_irq_handler(p_obj);

    return (p_obj->info.asynch.event & I2C_EVENT_ALL);
}

/*--------------------------------------------------*/
/**
  * @brief     Abort asynchronous transfer
  * @param     p_obj     :i2c object.
  * @retval    -
  * @note      For a non-blocking function.
  * @note      After error event occurred on i2c_slave_irq_handler_asynch_t,
  * @note      call this function and clear error status.
  * @attention This function is not available in interrupt.
  */
/*--------------------------------------------------*/
void i2c_slave_abort_asynch_t(_i2c_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef DEBUG
    assert_param(IS_POINTER_NOT_NULL(p_obj));
#endif /* #ifdef DEBUG */

    reset_asynch(p_obj);
    p_obj->info.asynch.state = I2C_TRANSFER_STATE_IDLE;
    I2C_slave_init(&p_obj->i2c);
    I2C_clear_int_status(&p_obj->i2c);
    clear_irq(p_obj->info.irqn);
}

/**
 *  @}
 */ /* End of group UTILITIES_Exported_functions */

/**
 *  @}
 */ /* End of group UTILITIES */

/**
 *  @}
 */ /* End of group Example */

#endif /* defined(__BSP_I2C_H)  */

#ifdef __cplusplus
}
#endif /* __cplusplus */