?? i2c.c
字號:
/*
i2c support for LPC21XX
(c) 2004 Yuri Tiomkin (yuri@tnkernel.com)
Includes drivers:
- EEPROM 24XX series (from 24XX04 to 24XX512)
- Real Time Clock DS1307
- I/O Extender PCA9555
- Temperature sensor LM75
Supports uCOS-II and TNKernel
THIS SOFTWARE IS PROVIDED BY THE YURI TIOMKIN 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 YURI TIOMKIN 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.
*/
#define __UCOS_ 1 //-- if uCOS-II is used
//#define __TNKERNEL_ 1 //-- if TNKernel is used
#include "LPC21XX.h"
#include "i2c.h"
#if defined(__UCOS_)
#include ".\\os\\includes.h"
#elif defined(__TNKERNEL_)
#include "..\\os\\tn.h"
#include "..\\os\\tn_port.h"
#endif
#ifndef NULL
#define NULL 0
#endif
#if defined(__UCOS_)
extern OS_EVENT * gpSemI2Cop;
#elif defined(__TNKERNEL_)
extern TN_SEM gSemI2Cop;
#endif
//===========================================================================
//================ Common routines ==========================================
//===========================================================================
void i2c_lpc_init(int Mode)
{
if(Mode == I2C_SPEED_400)
{
//--- I2C Timing for 58 MHz (t = 16.954 ns) ---
rI2C_I2SCLH = 47; //-- more then 0.6 us - 0.8
rI2C_I2SCLL = 93; //-- more then 1.3 us - 1.4
}
else //Slow
{
rI2C_I2SCLH = 47*4;
rI2C_I2SCLL = 93*4;
}
rI2C_I2CONCLR = 0xFF; //-- Clear all flags
rI2C_I2CONSET = 0x40; //-- Set Master Mode
rI2C_I2CONSET |= I2C_FLAG_I2EN; //--- Enable I2C
}
//---------------------------------------------------------------------------
static void i2c_lpc_wr_byte(int byte)
{
rI2C_I2DAT = byte;
rI2C_I2CONCLR = I2C_FLAG_SI; //-- Clear SI
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //-- End wr POINT
}
//---------------------------------------------------------------------------
static void i2c_lpc_stop()
{
//-- Set STOP condition
rI2C_I2CONCLR = I2C_FLAG_SI; //-- Clear SI
rI2C_I2CONSET |= I2C_FLAG_AA | I2C_FLAG_STO; //-- Clear NO ASK
}
//---------------------------------------------------------------------------
static int i2c_lpc_ctrl(int ctrl)
{
int chk;
//-- Set START
rI2C_I2CONCLR = 0xFF; // Clear all bits
rI2C_I2CONSET |= I2C_FLAG_I2EN | I2C_FLAG_STA;
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //--- End START
//-- Set ADDRESS
rI2C_I2DAT = ctrl;
rI2C_I2CONCLR = I2C_FLAG_STA | I2C_FLAG_SI; //-- Clear START & SI
if(ctrl & 1) //-- RD
chk = 0x40; //-- 40H - SLA+R has been transmitted; ACK has been received
else
chk = 0x18; //-- 18H - SLA+W has been transmitted; ACK has been received
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //-- End CTRL
if(rI2C_I2STAT != chk)
{
i2c_lpc_stop();
return I2C_ERR_NO_RESPONSE;
}
return I2C_NO_ERR;
}
//---------------------------------------------------------------------------
static int i2c_lpc_rx_to_buf(char * buf,int num)
{
int rc;
if(buf == NULL)
return I2C_ERR_WRONG_PARAM;
rc = num;
if(rc > 1)
{
rI2C_I2CONCLR = I2C_FLAG_SI;
rI2C_I2CONSET |= I2C_FLAG_AA;
for(;;)
{
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //-- End Data from slave;
*buf++ = (unsigned char)rI2C_I2DAT;
rc--;
if(rc <= 0)
break;
else if(rc == 1)
rI2C_I2CONCLR = I2C_FLAG_AA | I2C_FLAG_SI; //-- After next will NO ASK
else
{
rI2C_I2CONCLR = I2C_FLAG_SI;
rI2C_I2CONSET |= I2C_FLAG_AA;
}
}
}
else if(rc == 1)
{
rI2C_I2CONCLR = I2C_FLAG_AA | I2C_FLAG_SI; //-- After next will NO ASK
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //-- End Data from slave;
*buf = (unsigned char)rI2C_I2DAT;
}
else //err
return I2C_ERR_WRONG_PARAM;
return I2C_NO_ERR;
}
//----------------------------------------------------------------------
static int i2c_lpc_ask_polling_op(int ctrl) //-- wait until write finished
{
int rc;
int i;
#if defined(__UCOS_)
for(i=0;i < 15; i++)
#elif defined(__TNKERNEL_)
for(i=0;i < 15; i++)
#else
for(i=0;i < I2C_WR_24XX_TIMEOUT; i++) //-- actually wr = ~110 but timeout =10000
#endif
{
rI2C_I2CONSET = I2C_FLAG_STA;
rI2C_I2CONCLR = I2C_FLAG_SI; //-- Here - clear only SI (not all rI2C_I2CONCLR)
while(!(rI2C_I2CONSET & I2C_FLAG_SI)); //wait the ACK
rI2C_I2DAT = ctrl & 0xFE;; // R/WI = 0
rI2C_I2CONCLR = I2C_FLAG_SI | I2C_FLAG_STA; //-- Clear START & SI
while(!(rI2C_I2CONSET & I2C_FLAG_SI));//wait the ACK
rc = rI2C_I2STAT;
if(rc == 0x18) //-- got ACK after CLA + W
break;
else
{
#if defined(__UCOS_)
OSTimeDly(2); //-- 2 mS
#elif defined(__TNKERNEL_)
tn_task_sleep(2); //-- 2 mS
#endif
}
}
if(i == I2C_WR_24XX_TIMEOUT)
return I2C_ERR_24XX_WR_TIMEOUT;
return I2C_NO_ERR;
}
//===========================================================================
//================ EEPROM 24XX series ========================================
//===========================================================================
//----------------------------------------------------------------------------
static int m24xx_page_size(int eeprom_type, int eeprom_addr,int * pg_sz)
{
int page_size,rc;
page_size = 0;
rc = I2C_NO_ERR;
switch(eeprom_type)
{
case EEPROM_24XX04:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX04)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 16; // 24LC04B have page size = 16,24C04A = 8
break;
case EEPROM_24XX08:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX08)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 16;
break;
case EEPROM_24XX16:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX16)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 16;
break;
case EEPROM_24XX32:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX32)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 32;
break;
case EEPROM_24XX64:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX64)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 32;
break;
case EEPROM_24XX128:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX128)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 64;
break;
case EEPROM_24XX256:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX256)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 64;
break;
case EEPROM_24XX512:
if(eeprom_addr > EEPROM_MAX_ADDR_24XX512)
rc = I2C_ERR_24XX_BAD_ADDR;
else
page_size = 128;
break;
}
if(rc != I2C_NO_ERR)
return rc;
if(page_size == 0) //-- Bad eeprom_type
return I2C_ERR_24XX_BAD_TYPE;
if(pg_sz)
*pg_sz = page_size;
return I2C_NO_ERR;
}
//----------------------------------------------------------------------------
static int m24xx_set_addr(
int eeprom_type, //-- EEPROM type
int eeprom_addr, //-- start eeprom addr ( not included Hardware A2,A1,A0)
int eeprom_cs_val, //-- Hardware A2,A1,A0 (valid from 24XX32)
int * ctrl_val, //-- Value of ctrl(return)
int * addr_hi_val, //-- Value of addr_hi(return)
int * addr_lo_val) //-- Value of addr_lo(return)
{
int ctrl;
int addr_hi;
int addr_lo;
int rc;
rc = I2C_NO_ERR;
ctrl = 0;
addr_hi = 0;
addr_lo = 0;
switch(eeprom_type)
{
case EEPROM_24XX04: // 24LC04B ignore AO,A1,A2 pins
ctrl = (eeprom_addr>>7) & 0x02; //-- 00000010
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = eeprom_addr & 0xFF;
addr_lo = -1;
break;
case EEPROM_24XX08: // 24LC08B ignore AO,A1,A2 pins
ctrl = (eeprom_addr>>7) & 0x06; //-- 00000110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = eeprom_addr & 0xFF;
addr_lo = -1;
break;
case EEPROM_24XX16: // 24LC16B ignore AO,A1,A2 pins
ctrl = (eeprom_addr>>7) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = eeprom_addr & 0xFF;
addr_lo = -1;
break;
case EEPROM_24XX32:
ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = (eeprom_addr>>8) & 0x0F;
addr_lo = eeprom_addr & 0xFF;
break;
case EEPROM_24XX64:
ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = (eeprom_addr>>8) & 0x1F;
addr_lo = eeprom_addr & 0xFF;
break;
case EEPROM_24XX128:
ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = (eeprom_addr>>8) & 0x3F;
addr_lo = eeprom_addr & 0xFF;
break;
case EEPROM_24XX256:
ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = (eeprom_addr>>8) & 0x7F;
addr_lo = eeprom_addr & 0xFF;
break;
case EEPROM_24XX512:
ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
ctrl |= 0xA0; //-- 1010xxxx
addr_hi = (eeprom_addr>>8) & 0xFF;
addr_lo = eeprom_addr & 0xFF;
break;
}
if(rc != I2C_NO_ERR)
return rc;
if(ctrl == 0)
return I2C_ERR_24XX_BAD_TYPE;
if(ctrl_val)
*ctrl_val = ctrl;
if(addr_hi_val)
*addr_hi_val = addr_hi;
if(addr_lo_val)
*addr_lo_val = addr_lo;
return I2C_NO_ERR;
}
//----------------------------------------------------------------------------
static int i2c_lpc_m24xx_wr(
int eeprom_type, //-- EEPROM type
int eeprom_addr, //-- start eeprom addr ( not included Hardware A2,A1,A0)
int eeprom_cs_val, //-- Hardware A2,A1,A0 (valid from 24XX32)
char * buf, //-- Data srs buf
int num ) //-- Bytes to write qty
{
int rc;
int ctrl;
int addr_hi;
int addr_lo;
rc = m24xx_set_addr(eeprom_type,eeprom_addr,eeprom_cs_val,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -