#include "i2c.h"


/*
I2C seting:
fast mode 400KHz
coeficient of digital filter 5
*/
	void I2C_init(void)
	{
		RCC->APB1ENR1 |=RCC_APB1ENR1_I2C2EN;
		RCC->AHB2ENR  |=   RCC_AHB2ENR_GPIOBEN;

		GPIOB->AFR[1] &= ~((0x0FU<<8)|(0x0FU<<12)); //10 11
		GPIOB->AFR[1] |= ((0x04U<<8)|(0x04U<<12));
		GPIOB->MODER 	&= ~((0x03U<<20)|(0x03U<<22));
		GPIOB->MODER 	|= (0x02U<<20)|(0x02U<<22);
		GPIOB->OTYPER |= (0x01U<<10)|(0x01U<<11);
		GPIOB->OSPEEDR|= (0x03U<<20)|(0x03U<<22);
		GPIOB->PUPDR	&= ~((0x03U<<20)|(0x03U<<22));
		GPIOB->PUPDR	|= ((0x01U<<20)|(0x01U<<22));

		I2C2->CR1  = 0x05U<<8;
		I2C2->OAR1 = 0x01U<<15; 
		//I2C2->TIMINGR = 0xA0101B22;
		I2C2->TIMINGR = 0x00702480;
		I2C2->CR1 |= I2C_CR1_PE;
		I2C2->CR2 = I2C_CR2_AUTOEND | I2C_CR2_NACK;
	}
	
		
	uint8_t I2C_transmit(uint16_t address, uint8_t *data, uint16_t cnt)
	{
		uint16_t 	Tmp;
		uint8_t		Stat;
		while((I2C2->ISR & I2C_ISR_BUSY));  //waiting if line is busy 
		I2C2->CR2 &= ~(0xFFU<<16); //ensuring no remaining bits set in number of data to be transfered
		I2C2->CR2 &= ~(I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
		
		I2C2->CR2 &= ~(0x3FFU); //ensuring no remaining bits are set in address

		I2C2->CR2 &= ~(0x01U<<11);		//7bit address
		I2C2->CR2 &= ~(0x01U<<10);		//write 
		address 	&= ~0x01U;
		I2C2->CR2 |= ((address) & I2C_CR2_SADD) | I2C_CR2_NACK;

		do
		{
			if(cnt>255)		//comunication setting if amount of data is bigger then 255
			{
				I2C2->CR2 |= ((0xFFU<<16)|(I2C_CR2_RELOAD));
				I2C2->CR2 &= ~I2C_CR2_AUTOEND;
				Tmp=255;
				Stat=1;
				cnt-=255;
			}
			else	//comunication setting if amount of data is less then 255
			{
				I2C2->CR2 |= (((cnt)<<16 & I2C_CR2_NBYTES)|(I2C_CR2_AUTOEND));
				Tmp=cnt;
				Stat=0;
			}
				I2C2->CR2 |=I2C_CR2_START;
				
				while(Tmp)
				{
					while(!(I2C2->ISR & I2C_ISR_TXIS))
					if(I2C2->ISR & I2C_ISR_NACKF)
					{
						I2C2->ICR |= I2C_ICR_NACKCF;
						return Tmp;
					} 
					I2C2->TXDR=*data;
					data++;
					Tmp--;
				}
		}while(Stat);
		while(!(I2C2->ISR & I2C_ISR_STOPF)) {};
		I2C2->CR2 &= ~I2C_CR2_SADD;
		I2C2->ICR |= I2C_ICR_STOPCF;
		return 0;
	}


	uint8_t I2C_receive(uint16_t address, uint8_t *data, uint16_t cnt)
	{
		I2C2->CR2 &= ~(0xFFU<<16);						//ensuring no remaining bits set in number of data to be transfered
		while((I2C2->ISR & I2C_ISR_BUSY));		//waiting if line is busy 
		uint16_t 	Tmp;
		uint8_t		Stat;
		I2C2->CR2 &= ~(0x3FFU);								//ensuring no remaining bits are set in address

		I2C2->CR2 &= ~(0x01U<<11);						//7bit address
		I2C2->CR2 |= (0x01U<<10);							//read
		I2C2->CR2 |= (address) & I2C_CR2_SADD;

	do
	{
			if(cnt>255)
			{
				I2C2->CR2 |= ((0xFFU<<16)|(I2C_CR2_RELOAD));
				I2C2->CR2 &= ~I2C_CR2_AUTOEND;
				Tmp=255;
				Stat=1;
				cnt-=255;
			}
			else
			{
				I2C2->CR2 &= ~I2C_CR2_RELOAD;
				I2C2->CR2 |= ((((cnt)<<16)&I2C_CR2_NBYTES)|(I2C_CR2_AUTOEND));
				Tmp=cnt;
				Stat=0;
			}
				I2C2->CR2 |=I2C_CR2_START;
						while(Tmp)
						{

								while(!(I2C2->ISR & I2C_ISR_RXNE))
								{	
									if(I2C2->ISR & I2C_ISR_NACKF)
										{
										I2C2->ICR |= I2C_ICR_NACKCF;											
										return Tmp;
										}
								}
							*data++ = *(__IO uint8_t*)&I2C2->RXDR;
							Tmp--;
						}
		}while(Stat);

		I2C2->ICR |= I2C_ICR_STOPCF;
		I2C2->CR2 &= ~I2C_CR2_SADD;
		return 0;
	}




