📄 24c16nvram.c
字号:
/* 24c16NvRam.c - 24c16 EEPROM NVRAM driver */
/* Copyright 2002-2004 Founder Communications, Inc. */
/*
modification history
--------------------
01a,11apr05, fhchen written
*/
/*
DESCRIPTION
This file provides routines to read/write on board 24C16 EEPROM, and implement
sysNvRamSet/sysNvRamGet.
On V100R001 CPE board, GPIO205 is connected to SDA, GPIO206 connected to SCL,
GPIO208 connected to WP.
NOTE:
- Only byte write and random read supported.
- Timing is critical, use a 2-channel oscilloscope to view SDA and SCL.
*/
/* includes */
#include <vxWorks.h>
#include "24c16NvRam.h"
#include "sysGpio.h"
#include "config.h"
#ifdef INCLUDE_EEPROM
/* forward declaration */
LOCAL void i2cDelayNs(UINT32 ns);
LOCAL void i2cDelayUs(UINT32 us);
LOCAL void i2cDelayMs(UINT32 ms);
/* delay macro */
#define I2C_DELAY_NS(n) i2cDelayNs(n)
#define I2C_DELAY_US(n) i2cDelayUs(n)
#define I2C_DELAY_MS(n) i2cDelayMs(n)
/* gpio op macro */
#define I2C_SET_SDA(level) (sysGpioWrite(AT24C16_PORT, AT24C16_I2C_SDA, level))
#define I2C_SET_SCL(level) (sysGpioWrite(AT24C16_PORT, AT24C16_I2C_SCL, level))
#define I2C_GET_SDA(level) (level = sysGpioRead(AT24C16_PORT, AT24C16_I2C_SDA))
/* send op macro */
#define I2C_SEND_START i2cSendStart
#define I2C_SEND_STOP i2cSendStop
#define I2C_SEND_NOACK i2cSendNoAck
#define I2C_SEND_BIT(level) \
{ \
\
/* 1 */ \
\
I2C_SET_SCL(LOGIC_LOW); \
I2C_DELAY_US(1); \
\
I2C_SET_SDA(level); \
I2C_DELAY_US(AT24C16_DELAY); \
\
/* 2 */ \
\
I2C_SET_SCL(LOGIC_HIGH); \
I2C_DELAY_US(AT24C16_DELAY); \
}
#define I2C_SEND_BYTE(byteVal) i2cSendByte(byteVal)
/* receive op macro */
#define I2C_RECV_ACK i2cRecvAck
#define I2C_RECV_BIT(level) \
{ \
\
/* 1 */ \
\
I2C_SET_SCL(LOGIC_HIGH); \
\
I2C_GET_SDA(level); \
I2C_DELAY_US(AT24C16_DELAY); \
\
/* 2 */ \
\
I2C_SET_SCL(LOGIC_LOW); \
I2C_DELAY_US(AT24C16_DELAY); \
}
#define I2C_RECV_BYTE i2cRecvByte
/***********************************************************************
*
* i2cDelayNs - delay specified ns*10 nano-second
*
* Delay 10ns routine needed to get correct timing of I2C
*
* RETURNS: N/A
*/
LOCAL void i2cDelayNs
(
UINT32 ns /* 10ns to delay */
)
{
#if defined(DELAY_10NS)
DELAY_10NS(ns);
#endif
}
/***********************************************************************
*
* i2cDelayUs - delay specified us
*
* Delay us routine needed to get correct timing of I2C
*
* RETURNS: N/A
*/
LOCAL void i2cDelayUs
(
UINT32 us /* us to delay */
)
{
#if defined(DELAY_US)
DELAY_US(us);
#endif
}
/***********************************************************************
*
* i2cDelayMs - delay specified ms
*
* Delay ms routine needed to get correct timing of I2C
*
* RETURNS: N/A
*/
LOCAL void i2cDelayMs
(
UINT32 ms /* us to delay */
)
{
#if defined(DELAY_MS)
DELAY_MS(ms);
#endif
}
/***********************************************************************
*
* i2cSendStart - send I2C start condition
*
* This routine generate a I2C start condition, which is defined as: SDA
* change from high to low while SCL is high.
*
* RETURNS: N/A
*/
LOCAL void i2cSendStart(void)
{
/* 1 */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(AT24C16_DELAY);
I2C_SET_SDA(LOGIC_HIGH);
/* 2 */
I2C_SET_SCL(LOGIC_HIGH);
/* pull SDA high to low here */
I2C_DELAY_US(1);
I2C_SET_SDA(LOGIC_LOW);
I2C_DELAY_US(AT24C16_DELAY);
/* 3 */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(AT24C16_DELAY);
}
/***********************************************************************
*
* i2cSendStop - send I2C stop condition
*
* This routine generate a I2C stop condition, which is defined as: SDA
* change from low to high while SCL is high.
*
* RETURNS: N/A
*/
LOCAL void i2cSendStop(void)
{
/* 1 */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(AT24C16_DELAY);
I2C_SET_SDA(LOGIC_LOW);
/* 2 */
I2C_SET_SCL(LOGIC_HIGH);
/* pull SDA low to high here */
I2C_DELAY_US(1);
I2C_SET_SDA(LOGIC_HIGH);
I2C_DELAY_US(AT24C16_DELAY);
/* post */
I2C_SET_SCL(LOGIC_HIGH);
I2C_SET_SDA(LOGIC_HIGH);
}
/***********************************************************************
*
* i2cSendNoAck - send I2C No Ack
*
* This routine generate a I2C No Ack, which is defined as: SDA
* is high while SCL is in high.
*
* RETURNS: N/A
*/
LOCAL void i2cSendNoAck(void)
{
/* 1 */
I2C_SET_SCL(LOGIC_LOW);
I2C_SET_SDA(LOGIC_LOW);
I2C_DELAY_US(1);
I2C_SET_SDA(LOGIC_HIGH);
I2C_DELAY_US(1);
/* 2 */
I2C_SET_SCL(LOGIC_HIGH);
I2C_DELAY_US(AT24C16_DELAY);
/* 3 */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(1);
I2C_SET_SDA(LOGIC_LOW);
I2C_DELAY_US(1);
}
/***********************************************************************
*
* i2cSendByte - send 8 bits on SDA
*
* This routine send 8 bits via SDA, whatever it is, data or adress etc.
*
* RETURNS: N/A
*/
LOCAL void i2cSendByte(unsigned char byteVal)
{
unsigned char i = 8;
unsigned char bitVal;
/* send data */
for(i = 8; i > 0; i--)
{
bitVal = (byteVal >> (i - 1)) & 0x1;
I2C_SEND_BIT(bitVal);
}
/* post. !wave is not so good here! REFINE IT */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(1);
I2C_SET_SDA(LOGIC_LOW);
}
/***********************************************************************
*
* i2cRecvAck - receive I2C Ack
*
* This routine receive an I2C Ack, which is defined as: SDA
* is low while SCL is in high.
*
* RETURNS: OK or ERROR if it is not an ACK
*/
LOCAL STATUS i2cRecvAck(void)
{
int level;
/* pre: set SDA as input */
I2C_GET_SDA(level);
/* 1 */
I2C_SET_SCL(LOGIC_LOW);
I2C_DELAY_US(AT24C16_DELAY);
/* 2 */
I2C_SET_SCL(LOGIC_HIGH);
I2C_DELAY_US(1);
I2C_GET_SDA(level);
I2C_DELAY_US(AT24C16_DELAY);
/* post */
I2C_SET_SCL(LOGIC_LOW);
I2C_SET_SDA(LOGIC_LOW); /* set SDA as output */
I2C_DELAY_US(1); /* needed? */
return ((LOGIC_HIGH == level) ? ERROR : OK);
}
/***********************************************************************
*
* i2cRecvByte - receive 8 bits on SDA
*
* This routine receive 8 bits on SDA.
*
* RETURNS: OK or ERROR if it is not an ACK
*/
LOCAL char i2cRecvByte(void)
{
unsigned char i = 8;
unsigned char bitVal = 0;
char byteVal = 0;
/* pre */
I2C_SET_SCL(LOGIC_LOW);
/* get data */
for(i = 8; i > 0; i--)
{
I2C_RECV_BIT(bitVal);
byteVal |= ((bitVal == LOGIC_HIGH) ? 0x1 : 0x0);
if(i != 1)
byteVal <<= 1;
}
return byteVal;
}
/***********************************************************************
*
* at24c16Init - initialize resources used by this driver
*
* This routine set SDA and SCL to low, and disable protection.
*
* RETURNS: N/A
*/
void at24c16Init(void)
{
I2C_SET_SDA(LOGIC_LOW);
I2C_SET_SCL(LOGIC_LOW);
at24c16UnProtect();
}
/***********************************************************************
*
* at24c16UnProtect - disable protection
*
* This routine set WP pin to GND(low) to enable read and write.
*
* RETURNS: N/A
*/
void at24c16UnProtect(void)
{
sysGpioWrite(AT24C16_PORT, AT24C16_PIN_PROTECT, AT24C16_LOGIC_UNPROTECT);
}
/***********************************************************************
*
* at24c16ReadByte - read a byte
*
* This routine read a byte from 24c16 using Random Read Mode.
*
* RETURNS: OK or ERROR
*/
STATUS at24c16ReadByte
(
int address, /* address to read */
char * pByte /* byte just read */
)
{
/* I2C device address, upper 3 bit address of 24c16 and R/W */
char tempRead = ((AT24C16_I2C_ADDRESS << 4) |
(char)((address & 0x0700) >> 7) |
AT24C16_I2C_READ);
char tempWrite = ((AT24C16_I2C_ADDRESS << 4) |
(char)((address & 0x0700) >> 7) |
AT24C16_I2C_WRITE);
if((address < 0) || (address > AT24C16_MAX_SIZE) || (NULL == pByte))
return ERROR;
/*
* initiate a dummy write cycle
*/
/* send start condition */
I2C_SEND_START();
/* send preamble and recv ack */
I2C_SEND_BYTE(tempWrite), I2C_RECV_ACK();
/* send lower 8 bit address and recv ack */
I2C_SEND_BYTE(address & 0xFF), I2C_RECV_ACK();
/*
* initiate a real read cycle
*/
/* send start condition */
I2C_SEND_START();
/* send preamble and recv ack */
I2C_SEND_BYTE(tempRead), I2C_RECV_ACK();
/* recv the byte */
*pByte = I2C_RECV_BYTE();
/* send NOACK */
I2C_SEND_NOACK();
/* send stop condition */
I2C_SEND_STOP();
return OK;
}
/***********************************************************************
*
* at24c16WriteByte - write a byte
*
* This routine write a byte to 24c16 using Byte Write mode.
*
* RETURNS: OK or ERROR
*/
STATUS at24c16WriteByte
(
int address, /* address to write */
char byteVal /* byte to write */
)
{
/* I2C device address, upper 3 bit address of 24c16 and R/W */
char temp = ((AT24C16_I2C_ADDRESS << 4) |
(char)((address & 0x0700) >> 7) |
AT24C16_I2C_WRITE);
if((address < 0) || (address > AT24C16_MAX_SIZE))
return ERROR;
/* send start condition */
I2C_SEND_START();
/* send preamble and recv ack */
I2C_SEND_BYTE(temp), I2C_RECV_ACK();
/* send lower 8 bit address and recv ack */
I2C_SEND_BYTE(address & 0xFF), I2C_RECV_ACK();
/* send data to be written and recv ack */
I2C_SEND_BYTE(byteVal), I2C_RECV_ACK();
/* send stop condition */
I2C_SEND_STOP();
/* delay for Twr */
I2C_DELAY_MS(AT24C16_Twr);
return OK;
}
/***********************************************************************
*
* at24c16Erase - erase 24c16
*
* This routine erase 24c16 using the specified character.
*
* RETURNS: OK or ERROR
*/
STATUS at24c16Erase(char byteVal)
{
int address;
for(address = 0; address < AT24C16_MAX_SIZE; address++)
{
at24c16WriteByte(address, byteVal);
}
return OK;
}
#if (NV_RAM_SIZE != NONE)
/*******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
char data;
char temp;
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return ERROR;
while (strLen--)
{
data = *string;
at24c16WriteByte(offset, data);
/* verify data */
at24c16ReadByte(offset, &temp);
if (temp!= (UCHAR)data)
{
return ERROR;
}
string++, offset++;
}
return OK;
}
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string is terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
while (strLen--)
{
at24c16ReadByte(offset, string);
string++, offset++;
}
*string = EOS;
return (OK);
}
#endif /* NV_RAM_SIZE != NONE */
#endif /* INCLUDE_EEPROM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -