#include "at24cXX.h"
#include "uart.h"
#include "delay.h"

#define PAGE_SIZE	64

//引脚初始化
void I2C_init(void)
{
    SYS_EnableAPBClock(APB_MASK_GPIO2);
	SYS_DisableNJTRST();
    GPIO_SetHigh(IIC_SCL_PORT,IIC_SCL_PIN);
    GPIO_SetHigh(IIC_SDA_PORT,IIC_SDA_PIN);

    GPIO_SetOutput(IIC_WP_PORT,IIC_WP_PIN);
    GPIO_SetOutput(IIC_SCL_PORT,IIC_SCL_PIN);
    GPIO_SetOutput(IIC_SDA_PORT,IIC_SDA_PIN);

    //打开写保护
	IIC_WRITE_PROTECT_ENABLE();
}

/***********************iic**************************/

//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();
    IIC_SDA(1);//IIC_SDA = 1;
    IIC_SCL(1);//IIC_SCL = 1;
    delay_us(4);
    IIC_SDA(0);//IIC_SDA = 0;//START:when CLK is high,DATA change form high to low
    delay_us(4);
    IIC_SCL(0);//IIC_SCL = 0;
}


//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();
    IIC_SDA(0);//IIC_SDA = 0;
    IIC_SCL(0);//IIC_SCL = 0;
    delay_us(4);
    IIC_SCL(1);//IIC_SCL = 1;
    delay_us(4);
    IIC_SDA(1);//IIC_SDA = 1;
    delay_us(4);
}
//等待应答信号到来
//返回值：
//		1，接收应答失败
//    0，接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	volatile uint8_t ucErrTime=0;
    SDA_IN();  // SDA 配置成输入
    // IIC_SDA(1);//IIC_SDA=1;
    delay_us(1);
    IIC_SCL(1);//IIC_SCL=1;
    delay_us(1);
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
        IIC_Stop();
        return 1;
        }
    }
    IIC_SCL(0);//IIC_SCL=0;
    return 0;
  
}
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL(0);//IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA(0);//IIC_SDA = 0;
    delay_us(4);
    IIC_SCL(1);//IIC_SCL = 1;
    delay_us(2);
    IIC_SCL(0);//IIC_SCL = 0;
}
//不产生ACK应答
void IIC_NAck(void)
{
	IIC_SCL(0);//IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA(1);//IIC_SDA = 1;
    delay_us(4);
    IIC_SCL(1);//IIC_SCL = 1;
    delay_us(2);
    IIC_SCL(0);//IIC_SCL = 0;
}
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答
void IIC_Send_Byte(uint8_t txd)
{                    
	uint8_t t;
    SDA_OUT();
	IIC_SCL(0);//IIC_SCL=0;// 电平置低，开始传输数据
	for(t=0;t<8;t++)
	{
		// IIC_SDA=(txd&0x80)>>7;
		if((txd&0x80)>>7) IIC_SDA(1);
		else IIC_SDA(0);
		txd<<=1;
		delay_us(4);   //
		IIC_SCL(1);//IIC_SCL=1;
		delay_us(2);
		IIC_SCL(0);//IIC_SCL=0;
        if(t==7)
            SDA_IN();
		delay_us(2);
	}
}
//读1个字节，ack=1时，发送ACK，ack=0，发送nACK
uint8_t IIC_Read_Byte(uint8_t ack)
{
	uint8_t i,receive=0;
    SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL(0);//IIC_SCL=0;
        delay_us(4);
        IIC_SCL(1);//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:开始读数的地址
//返回值  :读到的数据
uint8_t AT24CXX_ReadOneByte(uint32_t ReadAddr)
{
	uint8_t temp;
	uint8_t 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(uint32_t WriteAddr,uint8_t DataToWrite)
{
	uint8_t 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(uint32_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)
{
//	OS_ERR err;
	uint8_t addrH,addrL;
	uint16_t lentmp,lentow,lens;
	uint8_t tmp;

	if(NumToRead==0)
		return;
	
//	I2C_init();
//	OSTimeDlyHMSM(0, 0, 0, 40, OS_OPT_TIME_DLY, &err);
//	delay_ms(1);//40
	// delay_us(500);
	
	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;//下一页的地址
	}
	//打开写保护
//	IIC_WRITE_PROTECT_ENABLE();
}
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
// 每128bytes为一个page,写操作不能跨页
void AT24CXX_Write(uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
{
	uint8_t addrH,addrL;
	uint16_t lentmp,lentow,lens;
	uint8_t tmp;
	
	if(NumToWrite==0)
		return;
	
	//关闭写保护
	IIC_WRITE_PROTECT_DISABLE();
//	delay_ms(1);//10
	delay_us(10);

	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();//产生一个停止条件
		// if(lentmp)
			delay_ms(6);
		//printf("at24 write %d %d %d, %d\r\n", WriteAddr, lens, addrH, addrL);
		WriteAddr=WriteAddr+lens;//下一页的地址
	}
  
//	delay_ms(10);//两次写操作，必须加间隔，否则写不进去	，最小5ms
	//打开写保护
	IIC_WRITE_PROTECT_ENABLE();
}
void AT24CXX_clr(uint32_t WriteAddr,uint32_t NumToWrite)
{
	uint8_t addrH,addrL;
	uint16_t lentmp,lentow,lens;
	uint8_t tmp;
	
	//关闭写保护
	IIC_WRITE_PROTECT_DISABLE();

	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;
	}
	//打开写保护
	IIC_WRITE_PROTECT_ENABLE();
	delay_ms(10);
}
//----------------------EEPROM---------------------------//
//--------------------------------------------------------EEPROM DATA

/*********************************************END OF FILE**********************/
#define I2C_DATA_LEN	512
uint8_t I2c_Buf_Write[I2C_DATA_LEN], I2c_Buf_Read[I2C_DATA_LEN];
/**
* @brief I2C(AT24C02)读写测试
* @param 无
* @retval 正常返回 1 ，不正常返回 0
*/
uint8_t I2C_Test(void)
{
	uint16_t 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+9;
	// 	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+1;
	}
	// AT24CXX_clr(512, I2C_DATA_LEN);
	// delay_ms(10);
	// AT24CXX_Read(512, I2c_Buf_Read, I2C_DATA_LEN);
	// data_dump("I2C Read", I2c_Buf_Read, I2C_DATA_LEN);
	// delay_ms(10);
	
	printf("1\n");
	AT24CXX_Write(512, I2c_Buf_Write, I2C_DATA_LEN);
	printf("2\n");
	delay_ms(10);
	printf("3\n");
	AT24CXX_Read(512, I2c_Buf_Read, 64);
	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;
}
