//=====================================================================
//文件名称：i2c.C
//功能概要：i2c底层驱动构件源文件
//制作单位：苏州大学嵌入式系统与物联网研究所(sumcu.suda.edu.cn)
//版    本：   2020-11-06  V2.0
//适用芯片：STM32
//=====================================================================
#include "i2c.h"
const static I2C_TypeDef* I2C_BASE[3] = {I2C1,I2C2,I2C3};
const static IRQn_Type    I2C_IRQ[3] = {I2C1_EV_IRQn,I2C2_EV_IRQn,I2C3_EV_IRQn,};

const uint32_t TIME_OUT = 0XFFFFEU;   //时间溢出


//======================================================================
//函数名称：i2c_init
//函数功能：初始化
//函数参数：I2C_No：I2C号；mode：模式；slaveAddress：本机地址；frequence：波特率
//函数说明：slaveAddress地址范围为0~127；frequence：10kb/s、100kb/s、400kb/s
//======================================================================
void i2c_init(uint8_t I2C_No,uint8_t mode,uint8_t Address,uint16_t frequence)
{
	uint8_t i=0;
	uint32_t temp;
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
    //（1）打开时钟门和设置为I2C功能
	switch(I2C_No)
	{
	case 0:    //    PTA9--SCL   PTA10--SDA
		RCC->APB1ENR1 |= RCC_APB1ENR1_I2C1EN_Msk;  //使能I2C1的时钟门
		RCC->CCIPR |= (1<<RCC_CCIPR_I2C1SEL_Pos);
		RCC->APB1ENR1 |= RCC_APB1ENR1_I2C1EN_Msk;  //使能I2C2的时钟门
		RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN_Msk;   //使能GPIOB的时钟门
        //设置GPIO模式
		GPIOA->MODER &= ~(GPIO_MODER_MODE10_Msk|GPIO_MODER_MODE9_Msk);
		GPIOA->MODER |= (2 << GPIO_MODER_MODE9_Pos) | (2 << GPIO_MODER_MODE10_Pos);
		//设置Open Drain
		GPIOA->OTYPER &= ~(GPIO_OTYPER_OT10_Msk | GPIO_OTYPER_OT9_Msk);
		GPIOA->OTYPER |= (1<<GPIO_OTYPER_OT10_Pos) | (1<<GPIO_OTYPER_OT9_Pos);
        //设置为上拉
		GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD10_Msk | GPIO_PUPDR_PUPD9_Msk);
		GPIOA->PUPDR |= (1<<GPIO_PUPDR_PUPD10_Pos) | (1<<GPIO_PUPDR_PUPD9_Pos);
		//设置速度
		GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED10_Msk | GPIO_OSPEEDR_OSPEED9_Msk);
		GPIOA->OSPEEDR |= ((3<<GPIO_OSPEEDR_OSPEED10_Pos) | (3<<GPIO_OSPEEDR_OSPEED9_Pos));
		//设置为I2C功能
		GPIOA->AFR[1] &=  ~(GPIO_AFRH_AFSEL10_Msk | GPIO_AFRH_AFSEL9_Msk);
		GPIOA->AFR[1] |= (4<<GPIO_AFRH_AFSEL10_Pos) | (4<<GPIO_AFRH_AFSEL9_Pos);
		break;
	case 1:  //    PTB10--SCL   PTB11--SDA
		RCC->CCIPR |= (1<<RCC_CCIPR_I2C2SEL_Pos);
		RCC->APB1ENR1 |= RCC_APB1ENR1_I2C2EN_Msk;  //使能I2C2的时钟门
		RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN_Msk;   //使能GPIOB的时钟门
        //设置GPIO模式
		GPIOB->MODER &= ~(GPIO_MODER_MODE10_Msk|GPIO_MODER_MODE11_Msk);
		GPIOB->MODER |= (2 << GPIO_MODER_MODE11_Pos) | (2 << GPIO_MODER_MODE10_Pos);
		//设置Open Drain
		GPIOB->OTYPER &= ~(GPIO_OTYPER_OT10_Msk | GPIO_OTYPER_OT11_Msk);
		GPIOB->OTYPER |= (1<<GPIO_OTYPER_OT10_Pos) | (1<<GPIO_OTYPER_OT11_Pos);
        //设置为上拉
		GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD10_Msk | GPIO_PUPDR_PUPD11_Msk);
		GPIOB->PUPDR |= (1<<GPIO_PUPDR_PUPD10_Pos) | (1<<GPIO_PUPDR_PUPD11_Pos);
		//设置速度
		GPIOB->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED10_Msk | GPIO_OSPEEDR_OSPEED11_Msk);
		GPIOB->OSPEEDR |= ((3<<GPIO_OSPEEDR_OSPEED10_Pos) | (3<<GPIO_OSPEEDR_OSPEED11_Pos));
		//设置为I2C功能
		GPIOB->AFR[1] &=  ~(GPIO_AFRH_AFSEL10_Msk | GPIO_AFRH_AFSEL11_Msk);
		GPIOB->AFR[1] |= (4<<GPIO_AFRH_AFSEL10_Pos) | (4<<GPIO_AFRH_AFSEL11_Pos);
		break;
	case 2:  //     PTC0--SCL  PTC1--SDA
		RCC->CCIPR |= (1<<RCC_CCIPR_I2C3SEL_Pos);      //选择系统时钟，system clock
		RCC->APB1ENR1 |= RCC_APB1ENR1_I2C3EN_Msk;      //使能I2C3的时钟门
		RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN_Msk;       //使能GPIOB的时钟门
        //设置GPIO模式
		GPIOC->MODER &= ~(GPIO_MODER_MODE0_Msk|GPIO_MODER_MODE1_Msk);
		GPIOC->MODER |= (2 << GPIO_MODER_MODE0_Pos) | (2 << GPIO_MODER_MODE1_Pos);
		//设置Open Drain
		GPIOC->OTYPER &= ~(GPIO_OTYPER_OT0_Msk | GPIO_OTYPER_OT1_Msk);
		GPIOC->OTYPER |= (1<<GPIO_OTYPER_OT0_Pos) | (1<<GPIO_OTYPER_OT1_Pos);
        //设置为上拉
		GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk | GPIO_PUPDR_PUPD1_Msk);
		GPIOC->PUPDR |= (1<<GPIO_PUPDR_PUPD0_Pos) | (1<<GPIO_PUPDR_PUPD1_Pos);
        //OSPEEDR设置为高速模式
		GPIOC->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0_Msk | GPIO_OSPEEDR_OSPEED1_Msk);
		GPIOC->OSPEEDR |= ((3<<GPIO_OSPEEDR_OSPEED0_Pos) | (3<<GPIO_OSPEEDR_OSPEED1_Pos));
		//设置为I2C功能
		GPIOC->AFR[0] &=  ~(GPIO_AFRL_AFSEL0_Msk | GPIO_AFRL_AFSEL1_Msk);
		GPIOC->AFR[0] |= (4<<GPIO_AFRL_AFSEL0_Pos) | (4<<GPIO_AFRL_AFSEL1_Pos);
		break;
	}
    //（1）清寄存器,复位I2C的寄存器值
    ptr->CR1 &= ~I2C_CR1_PE_Msk;
    for(i=0;i<100;i++);  //延时
    //（3）设置主从机模式
    if(mode == 1)
    {
        //配置I2C时钟
    	switch(frequence)
    	{
    	case 10:   //标准模式  10Khz
        	temp = (0xb << I2C_TIMINGR_PRESC_Pos) | (0xc7 << I2C_TIMINGR_SCLL_Pos) |\
        			(0xc3 << I2C_TIMINGR_SCLH_Pos) | (0x2 << I2C_TIMINGR_SDADEL_Pos) |\
    				(0x4 << I2C_TIMINGR_SCLDEL_Pos);
    		break;
    	case 100:  //标准模式  100Khz
        	temp = (0xb << I2C_TIMINGR_PRESC_Pos) | (0x13 << I2C_TIMINGR_SCLL_Pos) |\
        			(0xf << I2C_TIMINGR_SCLH_Pos) | (0x2 << I2C_TIMINGR_SDADEL_Pos) |\
    				(0x4 << I2C_TIMINGR_SCLDEL_Pos);
    		break;
    	case 400:  //FAST模式 400Khz
        	temp = (0x5 << I2C_TIMINGR_PRESC_Pos) | (0x9 << I2C_TIMINGR_SCLL_Pos) |\
        			(0x3 << I2C_TIMINGR_SCLH_Pos) | (0x4 << I2C_TIMINGR_SDADEL_Pos) |\
    				(0x3 << I2C_TIMINGR_SCLDEL_Pos);
    		break;
    	default:   //标准模式 100Khz
        	temp = (0xb << I2C_TIMINGR_PRESC_Pos) | (0x13 << I2C_TIMINGR_SCLL_Pos) |\
        			(0xf << I2C_TIMINGR_SCLH_Pos) | (0x2 << I2C_TIMINGR_SDADEL_Pos) |\
    				(0x4 << I2C_TIMINGR_SCLDEL_Pos);
    		break;
    	}

        ptr->TIMINGR = temp;
        ptr->CR1 |= I2C_CR1_PE_Msk;
    }
    else
    {
        //使能地址寄存器1，设置从机地址为slaveAddress
        ptr->OAR1 &= ~I2C_OAR1_OA1EN_Msk;
        ptr->OAR1 = (slaveAddress<<1) | I2C_OAR1_OA1EN_Msk;
        ptr->CR2 |= (I2C_CR2_AUTOEND | I2C_CR2_NACK);
        ptr->CR1 |= I2C_CR1_PE_Msk;//使能外设
    }
    for(i=0;i<100;i++);   //延时
}

//======================================================================
//函数名称：i2c_master_send
//函数功能：主机数据向从机写入数据
//函数参数：I2C_No：I2C号；slaveAddress：从机地址；data：待写入数据首地址
//函数说明：slaveAddress地址范围为0~127；
//======================================================================
uint8_t i2c_master_send(uint8_t I2C_No,uint8_t slaveAddress,uint8_t *data)
{
	uint32_t temp=0;
	uint32_t time = 0;
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];

    //（1）发送开始信号，
	temp = (slaveAddress<<1) | (1<<I2C_CR2_NBYTES_Pos);
	temp |= I2C_CR2_AUTOEND_Msk | I2C_CR2_START_Msk;
	ptr->CR2 = temp;  //配置发送从机地址，方向，字节数，自动结束
	//（2）接收数据
		ptr->ISR |= I2C_ISR_TXE_Msk;
		while((ptr->ISR & I2C_ISR_TXE_Msk) != I2C_ISR_TXE_Msk)
		{
			time++;
			if(time >= TIME_OUT)
			{
				return I2C_ERROR;
			}
		}
		ptr->TXDR = *data;
	//（3）等待结束信号
	time = 0;
	while((ptr->ISR & I2C_ISR_STOPF_Msk) != I2C_ISR_STOPF_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	ptr->ICR |= I2C_ICR_STOPCF_Msk;   //清停止标志位


	return I2C_OK; //发送成功
}

//======================================================================
//函数名称：i2c_master_receive
//函数功能：主机数据向从机读取数据
//函数参数：I2C_No：I2C号；slaveAddress：从机地址；data：数据存储区
//函数说明：slaveAddress地址范围为0~127；
//======================================================================
uint8_t i2c_master_receive(uint8_t I2C_No,uint8_t slaveAddress,uint8_t *data)
{
	uint32_t temp=0;
	uint32_t time = 0;
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
    //（1）发送开始信号，
	temp = (slaveAddress<<1) | (1<<I2C_CR2_NBYTES_Pos);
	temp |= I2C_CR2_RD_WRN_Msk | I2C_CR2_AUTOEND_Msk | I2C_CR2_START_Msk;
	ptr->CR2 = temp;
	//（2）发送数据
		while((ptr->ISR & I2C_ISR_RXNE_Msk) != I2C_ISR_RXNE_Msk)
		{
			time++;
			if(time >= TIME_OUT)
			{
				return I2C_ERROR;
			}
		}
		*data = ptr->RXDR;

	//（3）等待结束信号
	time = 0;
	while((ptr->ISR & I2C_ISR_STOPF_Msk) != I2C_ISR_STOPF_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	ptr->ICR |= I2C_ICR_STOPCF_Msk;   //清停止标志位
	return I2C_OK; //发送成功
}

//======================================================================
//函数名称：i2c_slave_send
//函数功能：从机向主机发送数据
//函数参数：I2C_No：I2C号；data：数据存储区
//函数说明：slaveAddress地址范围为0~127；
//======================================================================
uint8_t i2c_slave_send(uint8_t I2C_No,uint8_t *data)
{
	uint32_t time = 0;
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
	//（1）发送应答信号
	ptr->CR2 &= ~I2C_CR2_NACK_Msk;  //回复主机发送过来的地址信息
	//（2）消除地址接收标志位
	while((ptr->ISR & I2C_ISR_ADDR_Msk) != I2C_ISR_ADDR_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	ptr->ICR |= I2C_ICR_ADDRCF_Msk;  //清地址接收标志位
	//（3）等待为发送方向
	time = 0;
	while((ptr->ISR & I2C_ISR_DIR_Msk) != I2C_ISR_DIR_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	//（4）发送数据
	time=0;

		while((ptr->ISR & I2C_ISR_TXE_Msk) != I2C_ISR_TXE_Msk)
		{
			time++;
			if(time >= TIME_OUT)
			{
				return I2C_ERROR;
			}
		}
		ptr->TXDR = *data;

	//（5）等待停止信号
	time = 0;
	while((ptr->ISR & I2C_ISR_STOPF_Msk) != I2C_ISR_STOPF_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	ptr->ICR |= I2C_ICR_STOPCF_Msk;   //清停止标志位
	return I2C_OK;
}

//======================================================================
//函数名称：i2c_slave_receive
//函数功能：从机接收主机发送的数据
//函数参数：I2C_No：I2C号；data：数据存储区
//函数说明：slaveAddress地址范围为0~127；
//======================================================================
uint8_t i2c_slave_receive(uint8_t I2C_No,uint8_t *data)
{
	uint32_t time=0;
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];

	//（1）发送应答信号
	ptr->CR2 &= ~I2C_CR2_NACK_Msk;  //回复主机发送过来的地址信息
	//（2）消除地址接收标志位
	while((ptr->ISR & I2C_ISR_ADDR_Msk) != I2C_ISR_ADDR_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	ptr->ICR |= I2C_ICR_ADDRCF_Msk;   //清地址接收标志位
	//（3）等待方向为接收
	time = 0;
	while((ptr->ISR & I2C_ISR_DIR_Msk) == I2C_ISR_DIR_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	//（4）发送数据
	time = 0;

		ptr->ISR |= I2C_ISR_RXNE_Msk;
		while((ptr->ISR & I2C_ISR_RXNE_Msk) != I2C_ISR_RXNE_Msk)
		{
			time++;
			if(time >= TIME_OUT)
			{
				return I2C_ERROR;
			}
		}
		*data = ptr->RXDR;

	ptr->ICR |= I2C_ICR_STOPCF_Msk;    //清停止标志位
	//（5）发送非应答信号
	ptr->CR2 |=	I2C_CR2_NACK_Msk;
	time = 0;
	while((ptr->ISR & I2C_ISR_STOPF_Msk) != I2C_ISR_STOPF_Msk)
	{
		time++;
		if(time >= TIME_OUT)
		{
			return I2C_ERROR;
		}
	}
	return I2C_OK;
}

//======================================================================
//函数名称：i2c_enableInterput
//函数功能：开启接收中断
//函数参数：I2C_No：I2C号
//函数说明：无
//======================================================================
void i2c_R_enableInterput(uint8_t I2C_No)
{
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
	ptr->ISR |= I2C_ISR_RXNE|I2C_ISR_STOPF|I2C_ISR_TC_Msk|I2C_ISR_TCR_Msk|I2C_ISR_NACKF|I2C_ISR_ADDR_Msk;				//-----20210128
	ptr->CR1 |= I2C_CR1_RXIE_Msk|I2C_CR1_STOPIE|I2C_CR1_TCIE|I2C_CR1_NACKIE|I2C_CR1_ADDRIE;
	NVIC_EnableIRQ(I2C_IRQ[I2C_No]);
}

//======================================================================
//函数名称：i2c_disableInterput
//函数功能：禁止接收中断
//函数参数：I2C_No：I2C号
//函数说明：无
//======================================================================
void i2c_R_disableInterput(uint8_t I2C_No)
{
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
	ptr->ISR &= ~I2C_ISR_ADDR_Msk;
	ptr->CR1 &= ~I2C_CR1_RXIE_Msk;
	ptr->CR1 &= ~I2C_CR1_ADDRIE;
	NVIC_DisableIRQ(I2C_IRQ[I2C_No]);
}

//======================================================================
//函数名称：i2c_T_enableInterput
//函数功能：开启发送中断
//函数参数：I2C_No：I2C号
//函数说明：无
//======================================================================
void i2c_T_enableInterput(uint8_t I2C_No)
{
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
	ptr->ISR |= I2C_ISR_TXIS_Msk;
	ptr->CR1 |= I2C_CR1_TXIE_Msk;
	NVIC_EnableIRQ(I2C_IRQ[I2C_No]);

}

//======================================================================
//函数名称：i2c_T_disableInterput
//函数功能：禁止发送中断
//函数参数：I2C_No：I2C号
//函数说明：无
//======================================================================
void i2c_T_disableInterput(uint8_t I2C_No)
{
	I2C_TypeDef* ptr = (I2C_TypeDef*)I2C_BASE[I2C_No];
	ptr->CR1 &= ~I2C_CR1_TXIE_Msk;
	NVIC_DisableIRQ(I2C_IRQ[I2C_No]);
}



