#include "main.h"
#include "I2C_eeprom.h" 

//--------------------------724KHz-----------------sys:480MHz--------stm32H743-----------------

#define I2C_ADDR_READ		0xA1
#define I2C_ADDR_WRITE	0xA0

#define I2C_WP_PT()		LL_GPIO_SetOutputPin(GPIOD,LL_GPIO_PIN_11)
#define I2C_WP_UNPT()	LL_GPIO_ResetOutputPin(GPIOD,LL_GPIO_PIN_11)

#define I2C_SCL_HI()	LL_GPIO_SetOutputPin(GPIOD,LL_GPIO_PIN_12)
#define I2C_SCL_LO()	LL_GPIO_ResetOutputPin(GPIOD,LL_GPIO_PIN_12)

#define I2C_SDA_HI()	LL_GPIO_SetOutputPin(GPIOD,LL_GPIO_PIN_13)
#define I2C_SDA_LO()	LL_GPIO_ResetOutputPin(GPIOD,LL_GPIO_PIN_13)

#define SDA_VALUE()	((0x2000 & GPIOD->IDR)>>13)

static volatile unsigned short delay_4_pgm;

static volatile unsigned char delay_x_tick;

static void delay_x(void)
{
	for(delay_x_tick=0;delay_x_tick<16;delay_x_tick++);
}

static void I2C_SCL_hi(void)
{
	I2C_SCL_HI();delay_x();
}

static void I2C_SCL_lo(void)
{
	I2C_SCL_LO();delay_x();
}

static void I2C_SDA_hi(void)
{
	I2C_SDA_HI();delay_x();
}

static void I2C_SDA_lo(void)
{
	I2C_SDA_LO();delay_x();
}

static void wait(void)
{
	__nop();
	__nop();
	__nop();
	__nop();
}

static void I2C_start(void)
{
	I2C_SCL_lo();	//SCL low
	wait();
	I2C_SDA_lo();	//SDA low
	wait();
	I2C_SDA_hi();	//SDA high
	wait();
	I2C_SCL_hi();	//SCL high
	wait();
	I2C_SDA_lo();	//SDA goes low before the clock
	wait();
	I2C_SCL_lo();	//SCL low
	wait();
}

static void I2C_stop(void)
{
	I2C_SDA_lo();	//SDA low
	wait();
	I2C_SCL_hi();	//SCL high
	wait();
	I2C_SDA_hi();	//SDA goes from low to high when SCL is already high,
	wait();
}

static unsigned char I2C_send_byte(unsigned char bb)
{
	unsigned int i;
	unsigned char noack;
	unsigned char b,s;
	b=bb;
	for (i=8; i>0; i--)
	{
		I2C_SCL_lo();      		//Reset SCL
		wait();
		s = b >> 7;		//Send data to SDA pin
		if(1==(s & 0x01))I2C_SDA_hi();else I2C_SDA_lo();
		wait();
		I2C_SCL_hi();      		//Set SCL
		wait();
		I2C_SCL_lo();      		//Reset SCL
		wait();
		b<<=1;      		//Rotate data
	}
	I2C_SDA_hi();
	I2C_SCL_lo();				//Reset SCL
	wait();
	I2C_SCL_hi();        		//Set SCL
	wait();
	delay_x();
	delay_x();
	noack = SDA_VALUE();	//Check SDA for ACKN
	wait();
	I2C_SCL_lo();
	wait();
	I2C_SDA_lo();
	wait();
	return(noack);
}

static unsigned char I2C_read_byte(unsigned char ackn)
{
	unsigned int i;
	unsigned char ReceivedByte;

	ReceivedByte=0x0000;
	I2C_SDA_hi();	//Make SDA an input
	I2C_SCL_lo();	//Reset SCL
	for (i=8; i>0; i--)
	{
		wait();
		I2C_SCL_hi();				//Set SCL
		ReceivedByte <<= 1;		//Rotate data
		ReceivedByte |= SDA_VALUE();	//Read SDA -> data
		wait();
		I2C_SCL_lo();				//Reset SCL
		wait();
	}
	if(0==ackn)I2C_SDA_lo();else I2C_SDA_hi();	//SDA = ACK bit
	wait();
	I2C_SCL_hi();	//Set SCL
	wait();
	I2C_SCL_lo();	//Reset SCL
	wait();
	return(ReceivedByte);
}

unsigned int I2C_byte_write_via_page(unsigned int chip_cs, unsigned int addr, unsigned char *p, unsigned int len)
{
	unsigned int i;
	unsigned char data;
	unsigned char addr_hi,addr_lo;
	unsigned int i2c_page_size;
	unsigned char i2c_addr_write_cmd;
	unsigned char offset;
	
	if(chip_cs){
		i2c_page_size = I2C_PAGE_SIZE_24M01;
	}else{
		i2c_page_size = I2C_PAGE_SIZE_24512;
	}
	
	offset = addr & (i2c_page_size - 1);
	if((offset + len) > i2c_page_size)return 1;
	
	if(chip_cs)i2c_addr_write_cmd = I2C_ADDR_WRITE | 0x08 | ((addr&0x00010000)>>15);
	else i2c_addr_write_cmd = I2C_ADDR_WRITE;
	
	I2C_WP_UNPT();
	
	addr_hi = (unsigned char)(addr >> 8);
	addr_lo = (unsigned char)(addr);
	
	I2C_start();
	if(!I2C_send_byte(i2c_addr_write_cmd))
	{
		if(!I2C_send_byte(addr_hi))
		{
			if(!I2C_send_byte(addr_lo))
			{
				for(i=0;i<len;i++)
				{
					data=*p;
					I2C_send_byte(data);
					p++;
				}
			}else return 1;
		}else return 1;
	}else return 1;
	I2C_stop();
	
	//for(delay_4_pgm = 0; delay_4_pgm < 8000; delay_4_pgm++);
	
	I2C_WP_PT();
	
	return 0;
}

unsigned int I2C_page_write(unsigned int chip_cs, unsigned int addr, unsigned char *p)
{
	unsigned int i;
	unsigned char data;
	unsigned char addr_hi,addr_lo;
	unsigned int i2c_page_size;
	unsigned char i2c_addr_write_cmd;
	
	if(chip_cs){
		i2c_page_size = I2C_PAGE_SIZE_24M01;
		addr_hi = (unsigned char)(addr >> 8);
		addr_lo = 0;
	}else{
		i2c_page_size = I2C_PAGE_SIZE_24512;
		addr_hi = (unsigned char)(addr >> 8);
		addr_lo = (unsigned char)(addr & 0x80);
	}
	
	if(chip_cs)i2c_addr_write_cmd = I2C_ADDR_WRITE | 0x08 | ((addr&0x00010000)>>15);
	else i2c_addr_write_cmd = I2C_ADDR_WRITE;
	
	I2C_WP_UNPT();
	
	I2C_start();
	if(!I2C_send_byte(i2c_addr_write_cmd))
	{
		if(!I2C_send_byte(addr_hi))
		{
			if(!I2C_send_byte(addr_lo))
			{
				for(i=0;i<i2c_page_size;i++)
				{
					data=*p;
					I2C_send_byte(data);
					p++;
				}
			}else return 1;
		}else return 1;
	}else return 1;
	I2C_stop();
	
	//for(delay_4_pgm = 0; delay_4_pgm < 8000; delay_4_pgm++);
	
	I2C_WP_PT();
	
	return 0;
}

unsigned int I2C_page_read(unsigned int chip_cs, unsigned int addr, unsigned char *p, unsigned int len)
{
	unsigned int i;
	unsigned char addr_hi,addr_lo;
	unsigned int i2c_page_size;
	unsigned int chip_size;
	unsigned char i2c_addr_write_cmd;
	unsigned char i2c_addr_read_cmd;
	
	if(chip_cs){
		i2c_page_size = I2C_PAGE_SIZE_24M01;
		chip_size = I2C_CHIP_SIZE_24M01;
	}else{
		i2c_page_size = I2C_PAGE_SIZE_24512;
		chip_size = I2C_CHIP_SIZE_24512;
	}
	
	if((addr + len) > chip_size)return 1;
	
	if(chip_cs){
		i2c_addr_write_cmd = I2C_ADDR_WRITE | 0x08 | ((addr&0x00010000)>>15);
		i2c_addr_read_cmd = I2C_ADDR_READ | 0x08 | ((addr&0x00010000)>>15);
	}else{
		i2c_addr_write_cmd = I2C_ADDR_WRITE;
		i2c_addr_read_cmd = I2C_ADDR_READ;
	}
	
	addr_hi = (unsigned char)(addr >> 8);
	addr_lo = (unsigned char)(addr);
	
	I2C_start();
	if(!I2C_send_byte(i2c_addr_write_cmd))
	{
		if(!I2C_send_byte(addr_hi))
		{
			if(!I2C_send_byte(addr_lo))
			{
				I2C_stop();
				I2C_start();
				I2C_send_byte(i2c_addr_read_cmd);
				for(i=0;i<len;i++)
				{
					if(i<(len - 1))
					{
						*p=I2C_read_byte(0);
					}
					else
					{
						*p=I2C_read_byte(1);
					}
					p++;
				}
			}else return 1;
		}else return 1;
	}else return 1;
	I2C_stop();
	return 0;	
}

/*
void I2C_page_write(unsigned int page_addr, unsigned char *p)
{
	unsigned int i;
	unsigned char data;
	unsigned char addr_hi,addr_lo;
	
	I2C_WP_UNPT();
	
	addr_hi = (unsigned char)(page_addr >> 8);
	addr_lo = (unsigned char)(page_addr&0xFF);
	
	I2C_start();
	if(!I2C_send_byte(I2C_addr_write))
	{
		if(!I2C_send_byte(addr_hi))
		{
			if(!I2C_send_byte(addr_lo))
			{
				for(i=0;i<I2C_PAGE_SIZE;i++)
				{
					data=*p;
					I2C_send_byte(data);
					p++;
				}
			}
		}
	}
	I2C_stop();
	
	for(delay_4_pgm = 0; delay_4_pgm < 8000; delay_4_pgm++);
	
	I2C_WP_PT();
}

void I2C_page_read(unsigned int page_addr, unsigned char *p)
{
	unsigned char i;
	unsigned char addr_hi,addr_lo;
	
	addr_hi = (unsigned char)(page_addr >> 8);
	addr_lo = (unsigned char)(page_addr&0xFF);
	
	I2C_start();
	if(!I2C_send_byte(I2C_addr_write))
	{
		if(!I2C_send_byte(addr_hi))
		{
			if(!I2C_send_byte(addr_lo))
			{
				I2C_stop();
				I2C_start();
				I2C_send_byte(I2C_addr_read);
				for(i=0;i<I2C_PAGE_SIZE;i++)
				{
					if(i<(I2C_PAGE_SIZE - 1))
					{
						*p=I2C_read_byte(0);
					}
					else
					{
						*p=I2C_read_byte(1);
					}
					p++;
				}
			}
		}
	}
	I2C_stop();	
}
*/
