#include "includes.h"
#include "trace.h"
#include "AT24C128.h"
#include "stdio.h"
//#include "sys.h"
#include "delay.h"

//#include "sys.h"


/*	AT24C128C  organized as 256 pages of 64-bytes each
	AT24C512C, organized as 512 pages of 128 bytes each
	不同的的EEPROM对应的页大小不一样，注意修改
*/

#define PAGE_SIZE	64
OS_SEM i2c_sem;

void I2C_init(void)
{
  
	OS_ERR      err;
	
  GPIO_InitTypeDef GPIO_InitStructure = {0};
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOB时钟
  
  //解除写保护
  GPIO_InitStructure.GPIO_Pin = IIC_WP_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//2MHz
	GPIO_Init(IIC_WP_PORT, &GPIO_InitStructure);
  
  //解除写保护
//  GPIO_ResetBits(IIC_WP_PORT,IIC_WP_PIN);
	
	//打开写保护
    GPIO_SetBits(IIC_WP_PORT,IIC_WP_PIN);
  
  //IIC时钟信号位
  GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
	GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_PIN);
  GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);//初始化
  
  //IIC数据信号位
  GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//OD
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
	GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_PIN);
  GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);//初始化

//	OSSemCreate(&i2c_sem, "i2c_sem", 1, &err);
}



u8 iic_cmd_delay=0;


/***********************iic**************************/
void delay_nop(void)
{
	unsigned int i;
	
	for(i=0;i<50;i++)
		__nop();
	
}
//产生IIC起始信号
void IIC_Start(void)
{
	/*while(iic_cmd_delay < E_DELAY)	// 距上一个命令时间太短
	{
		R_WDT_Restart();
	}*/

	SDA_OUT();//sda线输出
	IIC_SDA = 1;
	IIC_SCL = 1;
	delay_us(4);
  IIC_SDA = 0;//START:when CLK is high,DATA change form high to low
	delay_us(4);
	IIC_SCL = 0;//钳住I2C总线，准备发送或接收数据
	

}


//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SDA = 0;
	IIC_SCL = 0;
	delay_us(4);
	IIC_SCL = 1;
  IIC_SDA = 1;//发送I2C总线结束信号
	delay_us(4);

	iic_cmd_delay=0;
}
//等待应答信号到来
//返回值：
//		1，接收应答失败
//    0，接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;
  
}
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL = 0;
	SDA_OUT();//sda线输出
	IIC_SDA = 0;
	delay_us(4);
	IIC_SCL = 1;
	delay_us(2);
	IIC_SCL = 0;
}
//不产生ACK应答
void IIC_NAck(void)
{
	IIC_SCL = 0;
	SDA_OUT();//sda线输出
	IIC_SDA = 1;
	delay_us(4);
	IIC_SCL = 1;
	delay_us(2);
	IIC_SCL = 0;
}
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答
void IIC_Send_Byte(u8 txd)
{                    
  u8 t;   	    
  IIC_SCL=0;//拉低时钟开始数据传输
  SDA_OUT(); 
  for(t=0;t<8;t++)
  {              
    IIC_SDA=(txd&0x80)>>7;
//    SDA_OUT(); 
//    if((txd&0x80)>>7)
//      IIC_SDA=1;
//    else
//      IIC_SDA=0;
    txd<<=1; 	  
    delay_us(4);   //对TEA5767这三个延时都是必须的
    IIC_SCL=1;
    delay_us(2); 
    IIC_SCL=0;	
    delay_us(2);
    
  }	
}
//读1个字节，ack=1时，发送ACK，ack=0，发送nACK
u8 IIC_Read_Byte(u8 ack)
{
	u8 i,receive=0;
	SDA_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
	{
    IIC_SCL=0; 
    delay_us(4);
		IIC_SCL=1;
    receive<<=1;
    if(READ_SDA)receive++;   
      delay_us(1); 
  }					 
  if (!ack)
    IIC_NAck();//发送nACK
  else
    IIC_Ack(); //发送ACK   
  return receive;
}


/***********************以上为IIC驱动**************************/












/***********************iic**************************/
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u32 ReadAddr)
{
	u8 temp;
	u8 addrH,addrL;

	addrH=ReadAddr>>8;
	addrL=ReadAddr&0xff;

	IIC_Start();

	IIC_Send_Byte(0xa0);

	IIC_Wait_Ack();
	IIC_Send_Byte(addrH);   //发送高地址
	IIC_Wait_Ack();
   	IIC_Send_Byte(addrL);   //发送低地址
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Send_Byte(0xa1);         //进入接收模式

	IIC_Wait_Ack();
	temp=	IIC_Read_Byte(0);
	IIC_Stop();//产生一个停止条件

	delay_us(4);
	return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite)
{
	u8 addrH,addrL;

	addrH=WriteAddr>>8;
	addrL=WriteAddr&0xff;

	IIC_Start();

	IIC_Send_Byte(0xa0);

	IIC_Wait_Ack();
	IIC_Send_Byte(addrH);   //发送高地址
	IIC_Wait_Ack();
	IIC_Send_Byte(addrL);   //发送低地址
	IIC_Wait_Ack();
	IIC_Send_Byte(DataToWrite);     //发送字节
	IIC_Wait_Ack();
	IIC_Stop();//产生一个停止条件
  
	delay_ms(10);//两次写操作，必须加间隔，否则写不进去
}
//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
	u8 addrH,addrL;
	u16 lentmp,lentow,lens;
	u8 tmp;
  OS_ERR      err;
	CPU_SR_ALLOC();
	
	if(NumToRead==0)
		return;

	OS_CRITICAL_ENTER();  
		OSSemPend(&i2c_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
   I2C_init();
		delay_ms(100);//两次写操作，必须加间隔，否则写不进去
        IWDG_ReloadCounter();
	lentmp=NumToRead;
	while(lentmp)
	{
		tmp=ReadAddr%PAGE_SIZE;
		tmp=PAGE_SIZE-tmp;
		if(tmp>=lentmp)//当页剩余空间大于要写入的长度
		{
			lentow=lentmp;
		}
		else
		{
			lentow=tmp;//写入长度只能是剩余空间长度
		}
		lentmp=lentmp-lentow;//计算要在下一页写入的长度
		lens=lentow;
		addrH=ReadAddr>>8;
		addrL=ReadAddr&0xff;

		IIC_Start();

		IIC_Send_Byte(0xa0);//写
		IIC_Wait_Ack();

		IIC_Send_Byte(addrH);   //发送高地址
		IIC_Wait_Ack();
	   	IIC_Send_Byte(addrL);   //发送低地址
		IIC_Wait_Ack();

		delay_us(4);
		IIC_Start();
		IIC_Send_Byte(0xa1);  //读       //进入接收模式
		IIC_Wait_Ack();

		while(lentow)
		{
			*pBuffer=IIC_Read_Byte(1);
			pBuffer++;
			//ReadAddr++;
			lentow--;
		}
		IIC_Read_Byte(0);
		IIC_Stop();//产生一个停止条件

		delay_us(4);
		//printf("at24 read %d %d\r\n", ReadAddr, lens);
		ReadAddr=ReadAddr+lens;//下一页的地址
	}
	GPIO_SetBits(IIC_WP_PORT,IIC_WP_PIN);
	OSSemPost(&i2c_sem, OS_OPT_POST_ALL, &err);
	OS_CRITICAL_EXIT();

}
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
// 每128bytes为一个page,写操作不能跨页
void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	u8 addrH,addrL;
	u16 lentmp,lentow,lens;
	u8 tmp;
	OS_ERR      err;
	   CPU_SR_ALLOC();

	if(NumToWrite==0)
		return;

	OS_CRITICAL_ENTER();  
	OSSemPend(&i2c_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
	I2C_init();
       IIC_WRITE_PROTECT_OFF();
	delay_ms(10);//两次写操作，必须加间隔，否则写不进去
        IWDG_ReloadCounter();
	lentmp=NumToWrite;
	while(lentmp)
	{
		tmp=WriteAddr%PAGE_SIZE;
		tmp=PAGE_SIZE-tmp;
		if(tmp>=lentmp)//当页剩余空间大于要写入的长度
		{
			lentow=lentmp;
		}
		else
		{
			lentow=tmp;//写入长度只能是剩余空间长度
		}
		lentmp=lentmp-lentow;//计算要在下一页写入的长度
		lens=lentow;

		addrH=WriteAddr>>8;
		addrL=WriteAddr&0xff;

		IIC_Start();

		IIC_Send_Byte(0xa0);

		IIC_Wait_Ack();
		IIC_Send_Byte(addrH);   //发送高地址
		IIC_Wait_Ack();
		IIC_Send_Byte(addrL);   //发送低地址
		IIC_Wait_Ack();

		while(lentow--)
		{
			IIC_Send_Byte(*pBuffer);
			IIC_Wait_Ack();
			pBuffer++;
		}
		IIC_Stop();//产生一个停止条件
		delay_ms(10);
		//printf("at24 write %d %d %d, %d\r\n", WriteAddr, lens, addrH, addrL);
		WriteAddr=WriteAddr+lens;//下一页的地址
	}
  
	
	delay_ms(10);//两次写操作，必须加间隔，否则写不进去
	IIC_WRITE_PROTECT_ON();
	OSSemPost(&i2c_sem, OS_OPT_POST_ALL, &err);
	OS_CRITICAL_EXIT();

}
void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite)
{
	u8 addrH,addrL;
	u16 lentmp,lentow,lens;
	u8 tmp;

	lentmp=NumToWrite;
	while(lentmp)
	{
		tmp=WriteAddr%PAGE_SIZE;
		tmp=PAGE_SIZE-tmp;
		if(tmp>=lentmp)
		{
			lentow=lentmp;
		}
		else
		{
			lentow=tmp;
		}
		lentmp=lentmp-lentow;
		lens=lentow;

		addrH=WriteAddr>>8;
		addrL=WriteAddr&0xff;

		IIC_Start();

		IIC_Send_Byte(0xa0);

		IIC_Wait_Ack();
		IIC_Send_Byte(addrH);   //发送高地址
		IIC_Wait_Ack();
		IIC_Send_Byte(addrL);   //发送低地址
		IIC_Wait_Ack();

		while(lentow--)
		{
			IIC_Send_Byte(0xff);
			IIC_Wait_Ack();
		}
		IIC_Stop();//产生一个停止条件
		delay_ms(10);
		WriteAddr=WriteAddr+lens;
	}
  
	delay_ms(10);
}
//----------------------EEPROM---------------------------//
//--------------------------------------------------------EEPROM DATA

/*********************************************END OF FILE**********************/
#define I2C_DATA_LEN	256
u8 I2c_Buf_Write[I2C_DATA_LEN], I2c_Buf_Read[I2C_DATA_LEN];
/**
* @brief I2C(AT24C02)读写测试
* @param 无
* @retval 正常返回 1 ，不正常返回 0
*/
uint8_t I2C_Test(void)
{
	u16 i;

	I2C_init();

	EEPROM_INFO("\r\nI2C(AT24C128)字节读写测试\r\n");
	memset(I2c_Buf_Write, 0, I2C_DATA_LEN);
	memset(I2c_Buf_Read, 0, I2C_DATA_LEN);
	for ( i=0; i< I2C_DATA_LEN; i++ ) //填充缓冲
	{
		I2c_Buf_Write[i] = i;
		AT24CXX_WriteOneByte(i, i);
		I2c_Buf_Read[i] = AT24CXX_ReadOneByte(i);
	}
	data_dump("I2C Write", I2c_Buf_Write, I2C_DATA_LEN);
	data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN);

	EEPROM_INFO("\r\nI2C(AT24C128)连续地址读写测试\r\n");

	memset(I2c_Buf_Write, 0, I2C_DATA_LEN);
	memset(I2c_Buf_Read, 0, I2C_DATA_LEN);
	for ( i=0; i< I2C_DATA_LEN; i++ ) //填充缓冲
	{
		I2c_Buf_Write[i] = i+100;
	}
	AT24CXX_clr(I2C_DATA_LEN, I2C_DATA_LEN);
	AT24CXX_Read(I2C_DATA_LEN, I2c_Buf_Read, I2C_DATA_LEN);
	data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN);
	
	AT24CXX_Write(I2C_DATA_LEN, I2c_Buf_Write, I2C_DATA_LEN);
	AT24CXX_Read(I2C_DATA_LEN, I2c_Buf_Read, I2C_DATA_LEN);
	data_dump("I2C Write", I2c_Buf_Write, I2C_DATA_LEN);
	data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN);
	
	EEPROM_INFO("\r\nI2C(AT24C128)读写测试成功\r\n");

	return 1;
}


void Tmp75_read(u8 *pBuffer)
{

	u16 lentmp,lentow,lens;
	lentow = 2;
	
	IIC_Start();

	IIC_Send_Byte(0x90);//写
	IIC_Wait_Ack();

	IIC_Send_Byte(0x00);   //发送寄存器地址
	IIC_Wait_Ack();

	delay_us(4);
	IIC_Start();
	IIC_Send_Byte(0x91);  //读       //进入接收模式
	IIC_Wait_Ack();

	while(lentow)
	{
		*pBuffer=IIC_Read_Byte(1);
		pBuffer++;
		//ReadAddr++;
		lentow--;
	}
	IIC_Stop();//产生一个停止条件
}


float Temp_test(void)
{
	float temp_data,tmp;
	u8 Temp_buf[4];
	
	I2C_init();
	
	Tmp75_read(Temp_buf);
	//data_dump("temp Read", Temp_buf, 2);
	
	tmp = (float)(Temp_buf[1]>>4);
	tmp /= 16.0;
	temp_data = (float)Temp_buf[0] + tmp;
//	printf("\ntmp: ");
//	printf("%.4f ℃\n",temp_data);
	
	return temp_data;
}

