⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 基于ecos的redboot
💻 C
字号:
/* i2c.c
---------------------------------------------------------------------------
                 Copyright (c) 2002, 2003 Intel Corporation
						 All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. 
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. 
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      
---------------------------------------------------------------------------
system: IXDP2400
subsystem: BootMonitor
author: gvaddadi
revisions:
--------------------------------------------------------------------------
*/

#include <cyg/io/i2c.h>
#include <cyg/hal/hal_ixdp2400.h>
#include <redboot.h>

/*Function prototypes*/
static void I2C_CLK(unsigned char x);
static void I2C_DATA(unsigned char x);
static void i2c_start(void);
static void i2c_stop(void);
static unsigned char i2c_ReadBit(void);
static void i2c_WriteBit(unsigned char x);
static void i2c_writebyte(unsigned char data);
static unsigned char i2c_readbyte(void);
unsigned char i2c_device_busy(unsigned char);

/*i2c_ack_stat is 0 if there is no error. 
*bit 0 is 1 if ack is not recd after writing slave address in write mode.
*bit 1 is 1 if ack is not recd after writing word address, 
*bit 2 is 1 if ack is not recd after writing slave address in read mode, 
*bit 3 is 1 if ack not recd after sending a data byte.
*/

/*************************************************************************
Function Name	:	I2C_CLK
Input			:	HIGH or LOW
OutPut			:	None
Desc			:	sets the SCL pin low or high
**************************************************************************/
static void I2C_CLK(unsigned char x)
{
	int temp;

	switch(x)
	{
	case HIGH:
		REG_WRITE(GPIO_PDCR,CLOCK);
		temp = REG_READ(GPIO_PDCR);
		while(!(REG_READ(GPIO_PLR) & CLOCK));
		break;
	case LOW:
		REG_WRITE(GPIO_PDSR,CLOCK);
		temp = REG_READ(GPIO_PDSR);
		break;
	}
}

/*************************************************************************
Function Name	:	I2C_DATA
Input			:	High or Low
OutPut			:	None
Desc			:	Sets the SDA pin Low or High
**************************************************************************/
static void I2C_DATA(unsigned char x)
{
	int temp;

	switch(x)
	{
	case HIGH:
		REG_WRITE(GPIO_PDCR,DATA);
		temp = REG_READ(GPIO_PDCR);
		break;
	case LOW:
		REG_WRITE(GPIO_PDSR,DATA);
		temp = REG_READ(GPIO_PDSR);
		break;
	}
}

/*************************************************************************
Function Name	:	i2c_start
Input			:	None
OutPut			:	None
Desc			:	generate i2c start condition.Start Condition: High to 
Low transition of SDA when SCL is high
**************************************************************************/ 
static void i2c_start(void)
{
    /*SDA=1, SCL=1 */
	I2C_DATA(HIGH);
	I2C_CLK(HIGH);
	I2C_DELAY(CLOCK_HIGH_TIME);
	
	/*SCL=1, SDA=0*/
	I2C_DATA(LOW);
	I2C_DELAY(START_CONDITION_HOLD_TIME);
	
	/*SCL=0 SDA=0*/
	I2C_CLK(LOW);
	I2C_DELAY(CLOCK_LOW_TIME);
}

/*****************************************************************************
Function name	:	i2c_stop
Input			:	None
OutPut			:	None
Desc			:	Generate i2c stop condition:LOW to High transition of 
SDA when SCL is high
******************************************************************************/

static void i2c_stop(void)
{
	/*SCL=0, SDA=0 */
	I2C_DATA(LOW);
	I2C_DELAY(CLOCK_LOW_TIME*2);
	
	/*SCL=1, SDA=0*/
	I2C_CLK(HIGH);
	I2C_DELAY(CLOCK_HIGH_TIME*2);
	
	/*SCL=1 SDA=1*/
	I2C_DATA(HIGH);
	I2C_DELAY(STOP_CONDITION_HOLD_TIME);
}

/******************************************************************************
Function Name	:	i2c_ReadBit()
Input			:	none
OutPut			:	returns the read bit
Desc			:	read bit on sda
******************************************************************************/
static unsigned char i2c_ReadBit(void)
{
	unsigned char x;
	
	I2C_CLK(LOW);
	I2C_DELAY(CLOCK_LOW_TIME);
	I2C_CLK(HIGH);
	I2C_DELAY(CLOCK_LOW_TIME);
	x = (unsigned char)((*(unsigned long int*)(GPIO_PLR)) & DATA);
	I2C_CLK(LOW);
	I2C_DELAY(CLOCK_LOW_TIME);
    return ( (x & DATA) ? 1 : 0); 
}

/******************************************************************************
Function Name	:	i2c_WriteBit()
Input			:	bit to be written
OutPut			:	none
Desc			:	output a bit onto sda
******************************************************************************/
static void i2c_WriteBit(unsigned char x)
{
	I2C_CLK(LOW);
	I2C_DELAY(CLOCK_LOW_TIME/2);
	
	if (x & 0x80) /* the MSB is sent out first*/
		I2C_DATA(HIGH);
	else
		I2C_DATA(LOW);
	I2C_DELAY(CLOCK_LOW_TIME);
	I2C_CLK(HIGH);
	I2C_DELAY(CLOCK_HIGH_TIME);
	I2C_CLK(LOW);
	I2C_DELAY(CLOCK_LOW_TIME);
	
	I2C_DATA(HIGH);
}

/******************************************************************************
Function Name	:	i2c_writebyte
Input			:	byte to be written
OutPut			:	None
Desc			:	write a byte onto i2c 
******************************************************************************/

static void i2c_writebyte(unsigned char data)
{
	int i;
	
	for(i = 0; i < 8; i++)
	{
		i2c_WriteBit(data);
		data <<= 1;
	}
	I2C_DATA(HIGH);/*release SDA*/
}

/*****************************************************************************
Function Name	:	i2c_readbyte
Input			:	none
OutPut			:	returns the byte read from the i2c device
Desc			:	read a byte from i2c 
******************************************************************************/
static unsigned char i2c_readbyte(void)
{
	unsigned char bit;
	unsigned char data = 0x0;
	
	/*The MSB is read first*/
	for(data = 0, bit = 0; bit < 7; bit++)
	{
		data |= i2c_ReadBit();
		data <<= 1;
	}
	data |= i2c_ReadBit();
	
	return data;
}

/******************************************************************************
Function Name	:	i2c_init
Input			:	none
OutPut			:	none
Desc			:	configures the GPIO 7(SCL) and 6 (SDA) for output
******************************************************************************/
static void i2c_init(void)
{
    int i;

#if 0
	/*configure pin 7 and 6 to be output*/
	REG_WRITE(GPIO_PDSR, (CLOCK|DATA));
#endif
	
	/*make the output level on pins gpio 6 and 7 low*/
	REG_WRITE(GPIO_POCR, (CLOCK|DATA));	
	
	/*make pins 6 and 7 as input during init*/
	REG_WRITE(GPIO_PDCR, (CLOCK));
	
	for(i = 0; i < 10; i++);

	REG_WRITE(GPIO_PDCR, (DATA));
	i = REG_READ(GPIO_PDCR);
}

void i2c_init0(void)
{
	/* initially at power up SDA has pull down because it is used as strap pin.
	* the PCI_ARB strap pin which is GPIO 2 should be driven high inorder to 
	* have a pull up on SDA line. This is required by this board design
	*/
    
    REG_WRITE(GPIO_PDSR, (I2C_INIT_BIT)); 
	
	/*drive this pin high*/
	REG_WRITE(GPIO_POSR, (I2C_INIT_BIT));
	
    i2c_init();
}

/******************************************************************************
Function Name	:	i2c_read
Input			:	Address of slave device to be read,
location to be read
ptr where read data has to be  stored
OutPut			:	none
Desc			:	read a byte of data(random read) on to i2c device
******************************************************************************/
int i2c_read(unsigned char slave, unsigned char addr, unsigned char *x)
{
	unsigned char data = NULL_DEV_ID;
	unsigned char ack1, ack2, i2c_ack_stat;
	
	i2c_ack_stat = 0x0;
	if(!i2c_device_busy(slave))
	{
		i2c_writebyte(addr);
		ack1 = i2c_ReadBit(); /*read ack from slave*/
		if(ack1 != 0)
			i2c_ack_stat |= 0x2; 
		
		i2c_start();
		i2c_writebyte(slave | I2C_READ);
		ack2 = i2c_ReadBit();
		if(ack2 != 0)
			i2c_ack_stat |= 0x3;
		data = i2c_readbyte();
        
		i2c_WriteBit(0x80); /*send nack*/
		i2c_stop();
	}
    else
        return I2C_ERROR;
	
	if(i2c_ack_stat != 0)
    {
		printf("Error in read, ack not recd, i2c_ack_stat=0x%x\n", i2c_ack_stat);
        return I2C_ERROR;
    }
	
	*x = data;
	return I2C_NOERR;
}

/******************************************************************************
Function Name	:	i2c_seq_read
Input			:	Address of slave device to be read,
starting location to be read, 
no.of locations to be read
ptr where the read data has to be stored
OutPut			:	none
Desc			:	read a byte of data(random read) on to i2c device
******************************************************************************/
int i2c_seq_read(unsigned char slave, unsigned char addr, 
				 unsigned char *data, unsigned char count)
{
	int i;
	unsigned char ack1, ack2, i2c_ack_stat;

	i2c_ack_stat = 0x0;
	
	if(!i2c_device_busy(slave))
	{
		i2c_writebyte(addr);
		ack1 = i2c_ReadBit(); /*read ack from slave*/
		if(ack1 != 0)
			i2c_ack_stat |= 0x2;
		
		i2c_start();
		i2c_writebyte(slave | I2C_READ);
		ack2 = i2c_ReadBit();
		if(ack2 != 0)
			i2c_ack_stat |= 0x4;
		for(i = 0; i < count; i++)
		{
			data[i] = i2c_readbyte();
			
			if(i != (count-1))
            {
                i2c_WriteBit(0x0); /*send ack*/
            }
            else
            { 
                i2c_WriteBit(0x80); /*send nack after reading the last byte*/
            }
		}
		i2c_stop();
	}
    else
        return I2C_ERROR;
	
	if(i2c_ack_stat != 0)
    {
		printf("Error in seq read, ack not recd, i2c_ack_stat=0x%x\n", i2c_ack_stat);
        return I2C_ERROR;
    }
	
	return I2C_NOERR;
}


/******************************************************************************
Function Name	:	i2c_write
Input			:	Address of the slave device to be written, 
location to be wriiten, 
data to be written
OutPut			:	none
Desc			:	Write a byte of data on to i2c device
******************************************************************************/
void i2c_write(unsigned char slave, unsigned char addr, unsigned char data)
{
	unsigned char ack1, ack2, i2c_ack_stat;

	i2c_ack_stat = 0x0;
	
	if(!i2c_device_busy(slave))
	{
		i2c_writebyte(addr);
		ack1 = i2c_ReadBit();
		if(ack1 != 0)
			i2c_ack_stat |= 0x2;
		i2c_writebyte(data);
		ack2 = i2c_ReadBit();
		if(ack2 != 0)
			i2c_ack_stat |= 0x8;
		i2c_stop();
	}
}

/******************************************************************************
Function Name	:	i2c_page_write
Input			:	Address of the slave device to be written, 
location to be wriiten, 
ptr to data array to be written
OutPut			:	I2C_ERROR or I2C_NOERR
Desc			:	Write a byte of data on to i2c device
******************************************************************************/
int i2c_page_write(unsigned char slave, unsigned char addr, 
				   unsigned char * data, unsigned char count)
{	
	int i;
	unsigned char ack1, ack2, i2c_ack_stat;

	i2c_ack_stat = 0x0;
	
	if(count > 16)
		count = 16;
	
	if(!i2c_device_busy(slave))
	{
		
		i2c_writebyte(addr);
		ack1 = i2c_ReadBit(); 
		if(ack1 != 0)
			i2c_ack_stat |= 0x2;
		for(i = 0; i < count; i++)
		{
			i2c_writebyte(data[i]);
			ack2 = i2c_ReadBit();
			if(ack2 != 0)
				i2c_ack_stat |= 0x8;
		}
		i2c_stop();
	}
    else
        return I2C_ERROR;
	
	if(i2c_ack_stat != 0)
    {
		printf("Error in page write, ack not recd, i2c_ack_stat=0x%x\n", i2c_ack_stat);
        return I2C_ERROR;
    }
	
    return I2C_NOERR;
}

/*once the stop condition is issued to indicate the end of the host's write
*operation, the NM24c02/03 initialtes the internal write cycle. ACK polling 
*can be initiated immediately. This involves issuing the strat condition 
*followed by the slave address for write operation. if the i2c device is still
*busy, no ack is returned. if the device completed its internal write 
*operation, an ack will be returned and the master can then proceed with next 
*read or write operation. the following function implements the ACLk polling.
*/
unsigned char i2c_device_busy(unsigned char slave)
{
	unsigned char busy = 1;
	int i = 0;

	while((busy != 0) && (i < 100))
	{
		i2c_start();
		i2c_writebyte(slave);
		busy=i2c_ReadBit();
		if(busy)
			i2c_stop();
		i++;
	}
	return busy;	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -