/**
  ******************************************************************************
  * @file    lcm32f06x_i2c.c
  * @author  System R&D Team
  * @version V2.0.2
  * @date    10-April-2025
  * @brief   This file provides all the i2c firmware functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Hangzhou Lingxin Microelectronics Co.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "lcm32f06x_i2c.h"

/**
  * @name   I2C_DeInit
  * @brief  EN: Deinitializes I2C peripheral registers to their default reset values.
  *         CN: 将 I2C 外设寄存器初始化为其默认重置值。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval None
  */
void I2C_DeInit(I2C_TypeDef *I2Cx)
{
  RCC_APB0PeriphResetCmd(RCC_APB0Periph_I2C0, ENABLE);

  RCC_APB0PeriphResetCmd(RCC_APB0Periph_I2C0, DISABLE);
}

/**
  * @name   SlaveAckGeneralCall
  * @brief  EN: I2C Determine whether to return an ACK or NACK after receiving the General Call. 
  *         CN: I2C 收到 General Call 是否返回 ACK/NACK。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  status:
  *             @arg TRUE
  *             @arg FALSE
  * @retval None
  * @note   EN: This is valid only in slave mode.
  *         CN: 该函数仅在从机模式下有效。
  */
void SlaveAckGeneralCall(I2C_TypeDef *I2Cx, bool status)
{
  if (status == TRUE)
  {
    I2Cx->ACKGENERALCALL |= I2C_ACKGENERALCALL_ACK_GEN_CALL_Msk;
  }
  if (status == FALSE)
  {
    I2Cx->ACKGENERALCALL &= ~I2C_ACKGENERALCALL_ACK_GEN_CALL_Msk;
  }
}

/**
  * @name   I2C_GenerateGeneralCall
  * @brief  EN: I2C Determine whether to return an ACK or NACK after receiving the General Call. 
  *         CN: 产生 General Call 广播。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval None
  * @note   EN: After generating a General Call broadcast, it needs to be manually cleared.
  *         CN: 生成 General Call 广播后需要手动清除。
  */
void I2C_GenerateGeneralCall(I2C_TypeDef *I2Cx)
{
  I2Cx->TAR |= I2C_TAR_SPECIAL_Msk; 
  I2Cx->TAR &= ~I2C_TAR_GC_STR_Msk; 
}

/**
  * @name   I2C_ClearGeneralCall
  * @brief  EN: Clear the General Call broadcast.
  *         CN: 清除 General Call 广播。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval None
  */
void I2C_ClearGeneralCall(I2C_TypeDef *I2Cx)
{
  I2Cx->TAR &= ~I2C_TAR_SPECIAL_Msk;
}

/**
  * @name   I2C_GenerateStartByte
  * @brief  EN: Generate Start Byte command.
  *         CN: 产生 Start Byte 命令。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval None
  */
void I2C_GenerateStartByte(I2C_TypeDef *I2Cx)
{
  I2Cx->TAR |= I2C_TAR_SPECIAL_Msk;  // special set
  I2Cx->TAR |= I2C_TAR_GC_STR_Msk; // GC_OR_START set
}

/**
  * @name   I2C_SetFrequent
  * @brief  EN:  Set I2C frequency.
  *         CN:  设置I2C频率。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval None
  */
void I2C_SetFrequent(I2C_TypeDef *I2Cx, int sclClock)
{
  uint32_t tmpreg = 0;
  uint32_t freq, LCNT, HCNT, SPKLEN;
  RCC_ClocksTypeDef RCC_Clocks;
  SpeedSelectType Mode;
  tmpreg = I2Cx->CON;
  tmpreg &= 0xFFFFFFF9;
  if (sclClock <= 100000)
  {
    Mode = STANDARD_MODE;

    tmpreg |= I2C_SPEED_STANDARD_MODE;
  }
  else if (sclClock <= 400000)
  {
    Mode = FAST_MODE;
    tmpreg |= I2C_SPEED_FAST_MODE;
  }
  else if (sclClock <= 1000000)
  {
    Mode = HIGH_SPEED;
    tmpreg |= I2C_SPEED_FAST_MODE;
  }
  I2Cx->CON = tmpreg;
  RCC_GetClockFreq(&RCC_Clocks);
  freq = RCC_Clocks.I2C0_Frequency;
  SPKLEN = I2Cx->FSSPKLEN;
  LCNT = (freq - 2 * sclClock) / (2 * sclClock);
  HCNT = (LCNT - SPKLEN - 6);
  if ((HCNT + SPKLEN + 7 > 17) && (LCNT + 1 > 16))
  {
    if (Mode == STANDARD_MODE)
    {
      I2Cx->SSLCNT = LCNT;
      I2Cx->SSHCNT = HCNT;
    }
    else if (Mode == FAST_MODE)
    {
      I2Cx->FSLCNT = LCNT;
      I2Cx->FSHCNT = HCNT;
    }
    else if (Mode == HIGH_SPEED)
    {
      I2Cx->FSLCNT = LCNT;
      I2Cx->FSHCNT = HCNT;
    }
  }
}

/**
  * @name   I2C_TxFifoITthreshold
  * @brief  EN: Configure the threshold for TX-EMPTY interrupt triggering.
  *         CN: 配置 TX_EMPTY 中断触发的阈值。
  * @param  TxFifoValue:
  *         EN: Specify interrupt trigger threshold.
  *         CN: 指定中断触发阈值。
  *             @arg I2C_RX_FIFO_IT_0
  *             @arg I2C_RX_FIFO_IT_1
  *             @arg I2C_RX_FIFO_IT_2
  *             @arg I2C_RX_FIFO_IT_3
  *             @arg I2C_RX_FIFO_IT_4
  *             @arg I2C_RX_FIFO_IT_5
  *             @arg I2C_RX_FIFO_IT_6
  *             @arg I2C_RX_FIFO_IT_7
  * @retval None
  */
void I2C_TxFifoITthreshold(uint32_t TxFifoValue)
{
  assert_param(IS_I2C_TX_FIFO_IT(TxFifoValue));
  I2C0->TXTL = TxFifoValue;
}

/**
  * @name   I2C_RxFifoITthreshold
  * @brief  EN: Configure the threshold for TX-RX_FULL interrupt triggering.
  *         CN: 配置 RX_FULL 中断触发的阈值。
  * @param  RxFifoValue:
  *         EN: Specify interrupt trigger threshold.
  *         CN: 指定中断触发阈值。
  *             @arg I2C_RX_FIFO_IT_0
  *             @arg I2C_RX_FIFO_IT_1
  *             @arg I2C_RX_FIFO_IT_2
  *             @arg I2C_RX_FIFO_IT_3
  *             @arg I2C_RX_FIFO_IT_4
  *             @arg I2C_RX_FIFO_IT_5
  *             @arg I2C_RX_FIFO_IT_6
  *             @arg I2C_RX_FIFO_IT_7
  * @retval None
  */
void I2C_RxFifoITthreshold(uint32_t RxFifoValue)
{
  assert_param(IS_I2C_RX_FIFO_IT(RxFifoValue));
  I2C0->RXTL = RxFifoValue;
}

/**
  * @name   I2C_TransferHandling
  * @brief  EN: Configure the destination address for host transmission.
  *         CN: 配置主机传输的目标地址。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  Address:
  *         EN: Target address.
  *         CN: 目标地址。
  * @retval None
  * @note   EN: If I2C is only used as a slave, this register does not need to be 
  *             configured and the address cannot be between 0x00 to 0x07.
  *         CN: 若 I2C 只作为从机使用该寄存器无需配置且地址不能为 0x00~0x07。
  */
void I2C_TransferHandling(I2C_TypeDef *I2Cx, uint32_t Address)
{
  uint32_t tmpreg = 0;
  tmpreg = I2Cx->TAR;
  tmpreg &= (uint32_t)0xFFFFEC00;
  tmpreg |= Address;
  if (tmpreg & 0x00000300)
    tmpreg |= I2C_TAR_10ADDR_MAS_Msk; //主机设置10位通信地址
  else
    tmpreg &= ~I2C_TAR_10ADDR_MAS_Msk; //主机设置7位通信地址
  I2Cx->TAR = tmpreg;
}

/**
  * @name   I2C_SlaveAddressConfig
  * @brief  EN: The slave address stored when configuring I2C as a slave.
  *         CN: 配置 I2C 做从机时存储的从机地址。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  Address:
  *         EN: slave address.
  *         CN: 从机地址。
  * @retval None
  * @note   EN: If I2C is only used as a host, this register does not need to be 
  *             configured and is only valid when I2C is disabled.
  *         CN: 若 I2C 只作为主机使用该寄存器无需配置且该寄存器仅在 I2C 禁止时配置有效。
  */
void I2C_SlaveAddressConfig(I2C_TypeDef *I2Cx, uint32_t Address)
{
  I2Cx->SAR = Address & ((uint32_t)0x000003FF); // 从机设置地址。
}

/**
  * @name   I2C_Cmd
  * @brief  EN: Enables or disables the specified I2C peripheral.
  *         CN: 启用或禁用指定的 I2C 外设。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  NewState: 
  *         EN: New state of the I2C peripheral.
  *         CN: I2C 外设的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void I2C_Cmd(I2C_TypeDef *I2Cx, FunctionalState NewState)
{

  if (NewState != DISABLE)
  {
    /* Enable the selected I2C peripheral */
    I2Cx->ENABLE |= (I2C_ENABLE_ENABLE_Msk);
  }
  else
  {
    /* Disable the selected I2C peripheral */
    I2Cx->ENABLE &= (~I2C_ENABLE_ENABLE_Msk);
  }
}

/**
  * @name   I2C_StructInit
  * @brief  EN: Fills each I2C_InitStruct member with its default value.
  *         CN: 用默认值填充每个 I2C_InitStruct 成员。
  * @param  I2C_InitStruct:
  *         EN: pointer to a I2C_InitTypeDef structure that contains the 
  *             configuration information for the specified I2C peripheral.
  *         CN: 指向 I2C_InitTypeDef 结构的指针，该结构包含指定 I2C 外设的配置信息。
  * @retval None
  */
void I2C_StructInit(I2C_InitTypeDef *I2C_InitStruct)
{
  /*---------------- Reset I2C init structure parameters values --------------*/
  I2C_InitStruct->I2C_mode = I2C_MasterOnlyMode;                  //主机模式
  I2C_InitStruct->I2C_StopDetMaster = I2C_StopDet_MasterAlways;   //主机模式下的STOP_DET中断
  I2C_InitStruct->I2C_RxFifoFullHold = I2C_RxFifoFullHold_ENABLE; //决定I2C在RX FIFO达到RX_RX_BUFFER_DEPTH时是否hold总线
  I2C_InitStruct->I2C_TxEmptyIntr = I2C_TxEmptyIntr_ENABLE;       //控制TX_EMPTY中断的产生方式
  I2C_InitStruct->I2C_Speed = 400000;                             // SCL速率配置
  I2C_InitStruct->I2C_SlaveAddressedLength = I2C_SlaveAddressedLength_10bit; //I2C 从机模式时地址长度
  I2C_InitStruct->I2C_DualAddr = 0x0;                             //从机地址
  I2C_InitStruct->I2C_StopDetSlave = I2C_StopDet_SlaveActive;     //从机模式下产生 STOP_DET 中断条件
}

/**
  * @name   I2C_Init
  * @brief  EN: Initializes the I2C peripheral according to the specified
  *             parameters in the I2C_InitStruct.
  *         CN: 根据 I2C_InitStruct 中指定的参数初始化 I2C 外设。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  I2C_InitStruct:
  *         EN: pointer to a I2C_InitTypeDef structure that contains the 
  *             configuration information for the specified I2C peripheral.
  *         CN: 指向 I2C_InitTypeDef 结构的指针，该结构包含指定 I2C 外设的配置信息。
  * @retval None
  */
void I2C_Init(I2C_TypeDef *I2Cx, I2C_InitTypeDef *I2C_InitStruct)
{
  uint32_t tmpreg = 0;
  tmpreg = I2Cx->CON;
  tmpreg &= 0xFFFFF830;
  I2Cx->ENABLE &= (~I2C_ENABLE_ENABLE_Msk);
  if (I2C_InitStruct->I2C_mode & 0x01)
  {
    tmpreg |= (I2C_InitStruct->I2C_mode) | (I2C_InitStruct->I2C_TxEmptyIntr) | \
              (I2C_InitStruct->I2C_RxFifoFullHold) | (I2C_InitStruct->I2C_StopDetMaster);
  }
  else
  {
    tmpreg |= (I2C_InitStruct->I2C_mode) | (I2C_InitStruct->I2C_SlaveAddressedLength) | \
              (I2C_InitStruct->I2C_StopDetSlave) | (I2C_InitStruct->I2C_TxEmptyIntr) | \
              (I2C_InitStruct->I2C_RxFifoFullHold)| (I2C_InitStruct->I2C_DualAddr);
  }
  I2Cx->CON = tmpreg;
  if (I2C_InitStruct->I2C_mode & 0x01)
  {
    I2C_SetFrequent(I2Cx, I2C_InitStruct->I2C_Speed);
  }
}

/**
  * @name   I2C_ReadRegister
  * @brief  EN: Reads the specified I2C register and returns its value.
  *         CN: 读取指定的I2C寄存器并返回其值。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  I2C_Register:
  *         EN: specifies the register to read.
  *         CN: 指定要读的寄存器。
  * @retval None
  */
uint32_t I2C_ReadRegister(I2C_TypeDef *I2Cx, uint8_t I2C_Register)
{
  __IO uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  assert_param(IS_I2C_REGISTER(I2C_Register));

  tmp = (uint32_t)I2Cx;
  tmp += I2C_Register;

  /* Return the selected register value */
  return (*(__IO uint32_t *)tmp);
}

/**
  * @name   I2C_WriteData
  * @brief  EN: I2C writes data as the host.
  *         CN: I2C 作为主机写数据。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  Data:
  *         EN: Specify the data to be written.
  *         CN: 指定要写的数据。
  * @retval None
  */
void I2C_WriteData(I2C_TypeDef *I2Cx, uint8_t Data)
{
 /* Check the parameters */
	assert_param(IS_I2C_ALL_PERIPH(I2Cx));
	uint32_t tmpPreg;
	tmpPreg = I2Cx->DATACMD;
	tmpPreg &= 0xFFFFFE00; // 写
	tmpPreg |= Data;
	I2Cx->DATACMD = tmpPreg;
}

/**
  * @name   I2C_WriteData_Stop
  * @brief  EN: I2C acts as the host and adds the STOP stop bit after writing 
  *             the last frame of data.
  *         CN: I2C 作为主机写最后一帧数据后加 STOP 停止位。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  Data:
  *         EN: Specify the data to be written.
  *         CN: 指定要写的数据。
  * @retval None
  */
void I2C_WriteData_Stop(I2C_TypeDef *I2Cx, uint8_t Data)
{
 /* Check the parameters */
	assert_param(IS_I2C_ALL_PERIPH(I2Cx));
	uint32_t tmpPreg;
	tmpPreg = I2Cx->DATACMD;
	tmpPreg &= 0xFFFFFE00; // 写
	tmpPreg |= (1 << 9) | Data; // STOP
  I2Cx->DATACMD = tmpPreg;
}

/**
  * @name   I2C_ReadData
  * @brief  EN: I2C read data as the host.
  *         CN: I2C 作为主机读数据。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval EN: Data read.
  *         CN: 读到的数据。
  */
uint8_t I2C_ReadData(I2C_TypeDef *I2Cx)
{
  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));

  uint8_t tempData;
  I2Cx->DATACMD |= I2C_DATACMD_CMD_Msk; //读
  while (I2C_GetITStatus(I2C0, I2C_STATUS_RFNF) == RESET);
  tempData = ((uint8_t)(I2Cx->DATACMD & 0xff));

  return tempData;
}

/**
  * @name   I2C_ReadData
  * @brief  EN: I2C acts as the host and adds the STOP stop bit after reading 
  *             the last frame of data.
  *         CN: I2C 作为主机读最后一帧数据后加 STOP 停止位。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval EN: Data read.
  *         CN: 读到的数据。
  */
uint8_t I2C_ReadData_Stop(I2C_TypeDef *I2Cx)
{
  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  uint8_t tempData;
  uint32_t tmpPreg = 0;
  tmpPreg |= I2C_DATACMD_CMD_Msk | (1 << 9); //读+STOP
  I2Cx->DATACMD |= tmpPreg;
  while (I2C_GetITStatus(I2C0, I2C_STATUS_RFNF) == RESET);
  tempData = ((uint8_t)(I2Cx->DATACMD & 0xff));

  return tempData;
}

/**
  * @name   I2C_ReceiveData
  * @brief  EN: I2C receives data as a slave.
  *         CN: I2C 作为从机接收数据。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @retval EN: Data read.
  *         CN: 接收到的数据。
  */
uint32_t I2C_ReceiveData(I2C_TypeDef *I2Cx)
{
  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));

  uint32_t tempData;
  tempData = I2Cx->DATACMD & 0x08ff;

  return tempData;
}

/**
  * @name   I2C_SendData
  * @brief  EN: I2C sends data as a slave.
  *         CN: I2C 作为从机发送数据。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  Data:
  *         EN: Specify the data to be sent.
  *         CN: 指定要发送的数据。
  * @retval None
  */
void I2C_SendData(I2C_TypeDef *I2Cx, uint8_t Data)
{
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  I2Cx->DATACMD |= Data;
}

/**
  * @name   I2C_DMACmd
  * @brief  EN: Enable or disable the specified I2C peripheral DMA function.
  *         CN: 启用或禁用指定的 I2C 外设 DMA功能。
  * @param  I2Cx:
  *         EN: x is 0 to select I2C peripherals.
  *         CN: x 是 0 以选择 I2C 外设。
  * @param  NewState: 
  *         EN: New status of I2C peripheral DMA function.
  *         CN: I2C 外设 DMA 功能的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void I2C_DMACmd(I2C_TypeDef *I2Cx, uint32_t I2C_DMAReq, FunctionalState NewState)
{
  assert_param(IS_I2C_DMAReq(I2C_DMAReq));
  if (I2C_DMAReq == I2C_DMAReq_Rx)
  {
    (NewState != DISABLE) ? (I2Cx->DMACR |= I2C_DMAReq_Rx) : (I2Cx->DMACR &= ~I2C_DMAReq_Rx);
  }
  else
  {
    (NewState != DISABLE) ? (I2Cx->DMACR |= I2C_DMAReq_Tx) : (I2Cx->DMACR &= ~I2C_DMAReq_Tx);
  }
}

/**
  * @name   I2C_TxDMAITthreshold
  * @brief  EN: Configure the data level triggered by TX_DMA_FIFO interrupt.
  *         CN: 配置 TX_DMA_FIFO 中断触发的数据水平。
  * @param  TxFifoValue:
  *         EN: Specify interrupt trigger threshold.
  *         CN: 指定中断触发阈值。
  *             @arg I2C_TX_DMA_IT_0
  *             @arg I2C_TX_DMA_IT_1
  *             @arg I2C_TX_DMA_IT_2
  *             @arg I2C_TX_DMA_IT_3
  *             @arg I2C_TX_DMA_IT_4
  *             @arg I2C_TX_DMA_IT_5
  *             @arg I2C_TX_DMA_IT_6
  *             @arg I2C_TX_DMA_IT_7
  * @retval None
  */
void I2C_TxDMAITthreshold(uint32_t TxDMAValue)
{
  assert_param(IS_I2C_TX_DMA_IT(TxDMAValue));

  I2C0->DMATDLR = TxDMAValue;
}

/**
  * @name   I2C_RxDMAITthreshold
  * @brief  EN: Configure the data level triggered by RX_DMA_FIFO interrupt.
  *         CN: 配置 RX_DMA_FIFO 中断触发的数据水平。
  * @param  TxFifoValue:
  *         EN: Specify interrupt trigger threshold.
  *         CN: 指定中断触发阈值。
  *             @arg I2C_RX_DMA_IT_0
  *             @arg I2C_RX_DMA_IT_1
  *             @arg I2C_RX_DMA_IT_2
  *             @arg I2C_RX_DMA_IT_3
  *             @arg I2C_RX_DMA_IT_4
  *             @arg I2C_RX_DMA_IT_5
  *             @arg I2C_RX_DMA_IT_6
  *             @arg I2C_RX_DMA_IT_7
  * @retval None
  */
void I2C_RxDMAITthreshold(uint32_t RxDMAValue)
{
  assert_param(IS_I2C_RX_DMA_IT(RxDMAValue));
  I2C0->DMARDLR = RxDMAValue;
}

/**
  * @name   I2C_GetFlagStatus
  * @brief  EN: Obtain I2C raw interrupt status.
  *         CN: 获取 I2C 原始中断状态。
  * @param  I2C_FLAG:
  *         EN: The specified raw interrupt.
  *         CN: 指定的原始中断。
  *             @arg I2C_IT_MST_ADDR1_MATCH
  *             @arg I2C_IT_MST_ADDR0_MATCH
  *             @arg I2C_IT_PEC_ERROR
  *             @arg I2C_IT_TIME_OUT
  *             @arg I2C_IT_SMBUS_ALERT
  *             @arg I2C_FLAG_MST_ON_HOLD
  *             @arg I2C_FLAG_RESTART_DET
  *             @arg I2C_FLAG_GEN_CALL
  *             @arg I2C_FLAG_START_DET
  *             @arg I2C_FLAG_STOP_DET
  *             @arg I2C_FLAG_ACTIVITY
  *             @arg I2C_FLAG_RX_DONE
  *             @arg I2C_FLAG_TX_ABRT
  *             @arg I2C_FLAG_RD_REQ
  *             @arg I2C_FLAG_TX_EMPTY
  *             @arg I2C_FLAG_TX_OVER
  *             @arg I2C_FLAG_RX_FULL
  *             @arg I2C_FLAG_RX_OVER
  *             @arg I2C_FLAG_RX_UNDER
  * @retval None
  */
FlagStatus I2C_GetFlagStatus(I2C_TypeDef *I2Cx, uint32_t I2C_FLAG)
{
  assert_param(IS_I2C_GET_FLAG(I2C_FLAG));
  unsigned int tmpreg = 0;
  FlagStatus bitstatus = RESET;
  tmpreg = I2Cx->RAWINTRSTAT;
  tmpreg &= I2C_FLAG;
  if (tmpreg != 0)
  {
    /* I2C_FLAG is set */
    bitstatus = SET;
  }
  else
  {
    /* I2C_FLAG is reset */
    bitstatus = RESET;
  }
  return bitstatus;
}

/**
  * @name   I2C_GetITStatus
  * @brief  EN: Obtain I2C interrupt status.
  *         CN: 获取 I2C 中断状态。
  * @param  I2C_STATUS:
  *         EN: The specifiedinterrupt.
  *         CN: 指定的中断。
  *             @arg I2C_STATUS_SLV_HOLD_RXFIFO_FULL
  *             @arg I2C_STATUS_SLV_HOLD_TXFIFO_EMPTY
  *             @arg I2C_STATUS_MST_HOLD_RXFIFO_FULL
  *             @arg I2C_STATUS_MST_HOLD_TXFIFO_EMPTY
  *             @arg I2C_STATUS_SLV_ACTIVITY
  *             @arg I2C_STATUS_MST_ACTIVITY
  *             @arg I2C_STATUS_RFF
  *             @arg I2C_STATUS_RFNF
  *             @arg I2C_STATUS_TFE
  *             @arg I2C_STATUS_TFNF
  *             @arg I2C_STATUS_ACTIVITY
  * @retval None
  */
FlagStatus I2C_GetITStatus(I2C_TypeDef *I2Cx, uint32_t I2C_STATUS)
{
  assert_param(IS_I2C_GET_STATUS(I2C_STATUS));
  unsigned int tmpreg = 0;
  FlagStatus bitstatus = RESET;
  tmpreg = I2Cx->STATUS;
  tmpreg &= I2C_STATUS;
  if (tmpreg != 0)
  {
    /* I2C_FLAG is set */
    bitstatus = SET;
  }
  else
  {
    /* I2C_FLAG is reset */
    bitstatus = RESET;
  }

  return bitstatus;
}

/**
  * @name   I2C_ClearITPendingBit
  * @brief  EN: Clear pending interrupts.
  *         CN: 清除挂起的中断。
  * @param  I2C_IT:
  *         EN: The specified interrupt.
  *         CN: 指定的中断。
  *             @arg I2C_IT_MST_ADDR1_MATCH
  *             @arg I2C_IT_MST_ADDR0_MATCH
  *             @arg I2C_IT_PEC_ERROR
  *             @arg I2C_IT_TIME_OUT
  *             @arg I2C_IT_SMBUS_ALERT
  *             @arg I2C_IT_MST_ON_HOLD
  *             @arg I2C_IT_RESTART_DET
  *             @arg I2C_IT_GEN_CALL
  *             @arg I2C_IT_START_DET
  *             @arg I2C_IT_STOP_DET
  *             @arg I2C_IT_ACTIVITY
  *             @arg I2C_IT_RX_DONE
  *             @arg I2C_IT_TX_ABRT
  *             @arg I2C_IT_RD_REQ
  *             @arg I2C_IT_TX_EMPTY
  *             @arg I2C_IT_TX_OVER
  *             @arg I2C_IT_RX_FULL
  *             @arg I2C_IT_RX_OVER
  *             @arg I2C_IT_RX_UNDER
  *             @arg I2C_IT_ALL
  * @retval None
  */
void I2C_ClearITPendingBit(I2C_TypeDef *I2Cx, uint32_t I2C_IT)
{
  assert_param(IS_I2C_GET_IT(I2C_IT));
  /* Clear the selected flag */
  switch (I2C_IT)
  {
  //当I2C工作在从机模式下，并使能双地址功能后，IC_SAR1匹配另一主机的寻址时   #18 /When I2C operates in slave mode and enables the dual address function, IC-SAR1 matches the address of another host
  case I2C_IT_MST_ADDR1_MATCH:
      I2Cx->IC_CLR_ADDR1_MATCH;
  break;
  //当I2C工作在从机模式下，IC_SAR0匹配另一主机的寻址时  #17 / When I2C operates in slave mode and IC-SAR0 matches the addressing of another host
  case I2C_IT_MST_ADDR0_MATCH:
      I2Cx->IC_CLR_ADDR0_MATCH; 
  break;
  //I2C工作在SMBUS协议下开启PEC校验功能后，产生PEC校验错误  #16 /After enabling the PEC verification function under the SMBUS protocol, I2C generates a PEC verification error
  case I2C_IT_PEC_ERROR:
      I2Cx->IC_CLR_PEC_ERROR; 
  break;
  //当I2C工作在SMBUS协议下发生超时错误时  #15 /When a timeout error occurs while I2C is working under the SMBUS protocol
  case I2C_IT_TIME_OUT:
      I2Cx->IC_CLR_TIMEOUT; 
  break;  
  //当总线上某个设备向SMBALERT线上产发送低电平信号时  #14 /When a device on the bus sends a low-level signal to the SMBALERT line
  case I2C_IT_SMBUS_ALERT:
      I2Cx->IC_CLR_SMBUS_ALERT; 
  break;  
  //当master txfifo为空时，启用时钟延伸   #13  /Enable clock extension when the Master TXFIFO is null
  case I2C_IT_MST_ON_HOLD:;
    break; // auto clear by hardware
  // slave接收到restart信号进入中断使能   #12  /Lave receives the RESTART signal to enable the interrupt function
  case I2C_IT_RESTART_DET:
    I2Cx->CLRRESTARTDET;
    break;
  //从机进入响应广播地址进入中断   #11  /Slave machine enter response broadcast address enter interrupt
  case I2C_IT_GEN_CALL:
    I2Cx->CLRGENCALL;
    break;
  // I2C接口是否产生了start或者restart信号，master和slaver都适用    #10  /Whether the I2C interface generates a start or restart signal. This parameter applies to the master or SLAver interface
  case I2C_IT_START_DET:
    I2Cx->CLRSTARTDET;
    break;
  // i2c接口上是否产生了stop信号#9   /i2c接口上是否产生了stop信号
  case I2C_IT_STOP_DET:
    I2Cx->CLRSTOP_DET;
    break;
  // i2c active 标志中断#8  /I2c ACTIVE flag interrupt 
  case I2C_IT_ACTIVITY:
    I2Cx->CLRACTIVITY;
    break;
  //*从机*发送1byte，主机未应答（slave类型中断）   #7   /Slave sends 1byte, the host does not respond (slave type interrupt)
  case I2C_IT_RX_DONE:
    I2Cx->CLRRXDONE;
    break;
  //发送不能继续产生中断,master slave都适用#6  /The send cannot continue to generate interrupts. This applies to both master slaves
  case I2C_IT_TX_ABRT:
    I2Cx->CLRTXABRT;
    break;
  //从机准备发送数据前，拉低时钟直到写入数据后清除中断（从机模式中断） #5  /Before the slave is ready to send data, pull down the clock until the interrupt is cleared after the data is written (slave mode interrupt)
  case I2C_IT_RD_REQ:
    I2Cx->CLRRDREQ;
    break;
  // Txfifo empty intr #4
  case I2C_IT_TX_EMPTY:;
    break;
  // Txfifo 溢出中断   #3 /Overflow trap
  case I2C_IT_TX_OVER:
    I2Cx->CLRTXOVER;
    break;
  // Rxfifo 满中断#2   /Full interrupt
  case I2C_IT_RX_FULL:;
    break;
  // RXfifo上溢中断    #1 Overflow interrupt
  case I2C_IT_RX_OVER:
    I2Cx->CLRRXOVER;
    break;
  // rxfifo 被读空后接着读，产生下溢中断#0
  case I2C_IT_RX_UNDER:
    I2Cx->CLRRXUNDER;
    break;
  case I2C_IT_ALL:
    I2Cx->CLRINTR;
    break;
  default:
    printf("error has occur");
  }
}

/**
  * @name   I2C_ITConfig
  * @brief  EN: Enable or disable interrupts.
  *         CN: 启用或禁用中断。
  * @param  I2C_IT:
  *         EN: The specified interrupt.
  *         CN: 指定的中断。
  *             @arg I2C_IT_MST_ADDR1_MATCH
  *             @arg I2C_IT_MST_ADDR0_MATCH
  *             @arg I2C_IT_PEC_ERROR
  *             @arg I2C_IT_TIME_OUT
  *             @arg I2C_IT_SMBUS_ALERT
  *             @arg I2C_IT_MST_ON_HOLD
  *             @arg I2C_IT_RESTART_DET
  *             @arg I2C_IT_GEN_CALL
  *             @arg I2C_IT_START_DET
  *             @arg I2C_IT_STOP_DET
  *             @arg I2C_IT_ACTIVITY
  *             @arg I2C_IT_RX_DONE
  *             @arg I2C_IT_TX_ABRT
  *             @arg I2C_IT_RD_REQ
  *             @arg I2C_IT_TX_EMPTY
  *             @arg I2C_IT_TX_OVER
  *             @arg I2C_IT_RX_FULL
  *             @arg I2C_IT_RX_OVER
  *             @arg I2C_IT_RX_UNDER
  *             @arg I2C_IT_ALL
  * @param  NewState: 
  *         EN: New state of the I2C peripheral interrupts.
  *         CN: I2C 外设中断的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void I2C_ITConfig(I2C_TypeDef *I2Cx, uint32_t I2C_IT, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_I2C_GET_IT(I2C_IT));

  I2Cx->INTRMASK = 0x00000000;
  if (NewState != DISABLE)
  {
    /* Enable the selected I2C interrupts */
    I2Cx->INTRMASK |= I2C_IT;
  }
  else
  {
    /* Disable the selected I2C interrupts */
    I2Cx->INTRMASK &= ~I2C_IT;
  }
}

