CAT1161是一个比较冷门的串行E2ROM监控看门狗芯片,好像是周立功代理的。能够找到的应用资料很少。
这段时间我在尝试使用CAT1161,碰到的问题特别古怪,耗了不少时间。
我是使用模拟的I2C程序,一个老模块,在多个I2C器件中应用过。
首先是应答问题:
发送完从机地址等待应答时,从机始终无应答。
更换了3个新的CAT1161,均是如此。换下来的器件,都能在编程器中正常操作,说明器件正常,而我的I2C程序模块,有问题。
因为是相信老的应用过模块,怎么也找不出问题。无论是单步,或断点,都无法收到应答信号。
后来将断点放到,SLC高电平,接收应答信号后面,发现已经正常收到应答信号。但是SDA却是高电平,没有应答信号。感到很奇怪。
通过记录SDA信号,发现在看门狗输出复位后,SDA应答信号消失了。
原来,看门狗部分,并不独立于串行E2PROM,看门狗输出复位,也将串行E2PROM复位。
因此单步调试,或不恰当的断点,由于看门狗的干扰,将无法收到正常的应答信号。
连续读操作等待时序问题:
连续读操作时,刚开始,发现间隔一个地址,读操作出错一次。
读出的是错误的数据,但是CAT1161应答正常。
开始以为读操作需要延时。
后来发现,由于书写错误,主机应答信号有误。
随机读时序为:起始位 从机地址 (从机应答) 字节地址 (从机应答) 起始位 从机地址 (从机应答) 数据 (主机不应答) 停止位。
最后的(主机不应答),应该SDA输出高电平。错误的应答,SDA低电平,将导致连续读写出错。
正确的应答电平,就可以连续读写的。
这样说明,CAT1161设计上有问题,起始信号、还是停止信号,都不能初始化串行E2PROM。
以前带串行E2ROM监控看门狗芯片有用过,X5045、X4045。
X5045、X4045,看门狗独立,可控启动关闭看门狗,修改看门狗周期,应用更灵活,至今感觉存储数据可靠性很不错,没发现丢失数据的。
缺点是,单一的复位电平,若需要低电平复位的话,须选择 X5043、X4043,麻烦些。
I2C接口的是X4045、X4043,芯片不错,可很难买到,价格也比X5045高。几个编程器都不支持是X4045、X4043,不放心继续应用。
由于希望节省单片机端口使用,I2C总线级联多个器件,于是选择了CAT1161。
对CAT1161的担心主要是:
1、呆板的看门狗设计,固定1.6秒的复位周期,不可关闭。不可关闭,在ISP在线编程应用,肯定有麻烦,须作特殊处理。
2、串行E2PROM,起始信号、停止信号,都不能真正置位串行E2PROM。
不知道有没有这种情况,使用过程中,串行E2PROM出错不响应了,非得复位信号才能正常。
这样,真是没意思,单片机需要监控就算了,串行E2PROM也要监控操作。
针对这样情况,那么,设计上得做更多特殊处理。
比如,发现串行E2PROM出错了,等待MCU空闲,可以复位操作了;强制MCU死机,然后,看门狗动作。串行E2PROM正常了,恢复MCU工作环境,继续记录数据MCU。
真的挺麻烦的。
3、最后一个问题,CAT1161数据稳定性怎样,不会跟其它功能这么菜吧。没有信心。
哪位大侠有用过?麻烦说说。
另外问问“帖子问题分数”这是什么作用?
转贴 貳馬de筆記
http://blog.21ic.com/user1/4663/archives/2009/59114.html
CAT1161应用小结
CAT1161是一款i2c接口的内置EEPROM和看门狗的复位芯片,E2PROM大小为16Kb(2KB),看门狗监听SDA总线上电平变化,1.6s无变化时自动复位,理论上使用很方便,但由于本人第一次使用,而且对i2c总线也不是很了解,故还是应用中遇到了点问题,还好最终解决,对出现的问题简单总结下。
MCU使用的是C8051F120,内置1路I2C接口,这个芯片内设口线不是固定的,需要配置,这个就不多说了,看手册。很多人喜欢用IO口模拟I2C总线,反正我不太喜欢,还是用芯片自带的吧。
遇到的第一个问题是:I2C程序运行到发送完从机地址等待应答时,从机始终无应答,反复检查程序没看出端倪,浪费大量时间,遂怀疑芯片,更换之,果然换了后最起码有了应答。真恨这些奸商,拿些过期芯片糊弄人,后来检查这些芯片大部分都有问题,就两片暂时能用。
第二问题:连续写三个字节到三个不同地址里,紧接着读出,发现读错误,或读出的数据是其他地址里的,最终解决,原因是,每次读写时两次操作之间必须间隔约10ms,写时要时间间隔可以理解,因为EEPROM是在总线时序结束后才开始写,未写完前是不会接收下次操作的,所以写的太快可能第二次的就没写进去,但读时发现似乎也要时间间隔,感觉没道理,因为每次读操作时都会等待读时序结束后才会退出的,不知道什么原因。
/*纠正*/ 经论证: 写操作若不是每次等时序结束才退出的,那么两次写之间必须得延时,读操作因为是时序结束后才退出的,所以可以连续读,中间不需要延时。
第三个问题:关于选择性读操作,就是给个地址读个数据那种操作,手册里时序为:起始位 从机地址 (从机应答) 字节地址 (从机应答) 起始位 从机地址 (从机应答) 数据 (主机不应答) 停止位 。我就是栽在第二个起始位那里,最后用示波器才发现时序错的太离谱了,所以一定好处理好时序,这个很重要。
总之,会用之后就很简单了,最主要就是注意:延时、时序 。
当然,对新手而言,还要学会用示波器看时序,这个也很重要。
附 测试代码:
//##################################################################
//CAT1161测试
{
extern int rand();
uint ui_Test1;
uchar uc_Test2;
uchar uc_Test3;
ui_Test1 = 0;
//循环
while (1)
{
uc_Test2 = rand();
//CAT1161写操作
{
g_CAT1161_Write(ui_Test1, uc_Test2); //CAT1161写操作
//正常写入
if (gb_Slave_Busy == 0)
acc ++ ; //断点测试
//写入失败
else
{
acc ++ ; //断点测试
continue;
} //写入失败
} //CAT1161写操作
//CAT1161读操作
{
uc_Test3 = guc_CAT1161_Read(ui_Test1); //CAT1161读操作
//正常读出
if (gb_Slave_Busy == 0)
{
//读出匹配
if (uc_Test2 == uc_Test3)
acc ++;
//读出错误
else
{
acc ++ ; //断点测试
continue;
} //读出错误
} //正常读出
//读出失败
else
{
acc ++ ; //断点测试
continue;
} //读出失败
} //CAT1161读操作
ui_Test1 ++;
ui_Test1 &=0x07ff;
if (ui_Test1 == 0)
acc ++ ; //断点测试
} //循环
} //CAT1161测试
I2C驱动模块:
//##################################################################
//I2C总线起始位
//入口;
//出口:
//通讯池:
//功能:
//用法:
void I2cBus_Start(void) reentrant //I2C总线起始位
{
gb_Slave_Busy = 0; //从器件忙标志 复位
io_SDA = 1;
DELAY_50ns; //延时0.05us
io_SCL = 1;
DELAY_600ns; //延时0.6us
io_SDA = 0;
DELAY_600ns; //延时0.6us
io_SCL = 0;
DELAY_1200ns; //延时1.2us
} //I2C总线起始位
//##################################################################
//I2C总线终止位
//入口;
//出口:
//通讯池:
//功能:
//用法:
void I2cBus_Stop(void) reentrant //I2C总线终止位
{
io_SCL = 0;
DELAY_1200ns; //延时1.2us
io_SDA = 0;
DELAY_50ns; //延时0.05us
io_SCL = 1;
DELAY_600ns; //延时0.6us
io_SDA = 1;
DELAY_600ns; //延时0.6us
} //I2C总线终止位
//##################################################################
//I2C总线应答符
//入口; b_Ack = 0 有效应答
//出口:
//通讯池:
//功能:
//用法:
void I2cBus_Ack(void) reentrant //I2C总线应答符
{
io_SCL = 1;
DELAY_600ns; //延时0.6us
io_SCL = 0;
DELAY_1200ns; //延时1.2us
} //I2C总线应答符
//##################################################################
//I2C总线写入字符
//入口; uc_Data 须写入的8位字节
//出口: 收到应答符, 返回0; 未收到应答符, 返回1
//通讯池:
//功能: 将字符写入从器件, 然后接受应答
//用法:
void I2cBus_CharWr(uchar uc_Data) reentrant //I2C总线写入字符
{
uchar uc1;
//写入8个字节
for (uc1 = 0; uc1 < 8; uc1 ++ )
{
io_SDA = uc_Data & 0x80;
DELAY_50ns; //延时0.05us
io_SCL = 1;
uc_Data <<= 1;
DELAY_600ns; //延时0.6us
io_SCL = 0;
DELAY_1200ns; //延时1.2us
} //写入8个字节
io_SDA = 1;
io_SCL = 1;
DELAY_600ns; //延时0.6us
gb_Slave_Busy = io_SDA; //从器件忙标志 读应答符
io_SCL = 0;
DELAY_1200ns; //延时1.2us
} //I2C总线写入字符
//##################################################################
//I2C总线读出字符
//入口; uc_Data 须读出的8位字节
//出口:
//通讯池:
//功能: 向从器件读取数据
//用法:
uchar uc_I2cBus_CharRd(void) reentrant //I2C总线读出字符
{
uchar uc1, uc2;
io_SDA = 1;
//读出8个字节
for (uc1 = 0; uc1 < 8; uc1 ++ )
{
uc2 <<= 1;
io_SCL = 1;
//读入一位
if (io_SDA == 1)
uc2 ++;
io_SCL = 0;
DELAY_1200ns; //延时1.2us
} //读出8个字节
return (uc2);
} //I2C总线读出字符
//##################################################################
//CAT1161看门狗
//入口; 对应的寄存器数据
//出口:
//通讯池:
//功能:
//用法:
void g_CAT1161_WatchDog(void) reentrant //CAT1161看门狗
{
io_SCL = 0;
io_SDA = 0;
DELAY_50ns; //延时0.05us
DELAY_600ns; //延时0.6us
io_SDA = 1;
} //CAT1161看门狗
//##################################################################
//CAT1161读操作
//入口; ui_Adr 扇区地址
//出口: 读出的数据
//通讯池:
//功能: 读出一个数据
//用法:
uchar guc_CAT1161_Read(uint ui_Adr) reentrant //CAT1161读操作
{
uchar uc1, uc2;
//读操作
// 操作时间限制在10ms
for (uc1 = 0; uc1 < 250; uc1 ++)
{
//起始位
I2cBus_Start(); //I2C总线起始位
//I2C总线写入字符
// 寻址码写操作 高位地址
I2cBus_CharWr(b10100000 + ( ( * ( (uchar * ) & ui_Adr + 0) & b00000111) << 1) ); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
//低位地址
I2cBus_CharWr( * ( (uchar * ) & ui_Adr + 1) ); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
//重新起始位
I2cBus_Start(); //I2C总线起始位
//CAT1161寻址
I2cBus_CharWr(b10100001); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
//读出指定数据
uc2 = uc_I2cBus_CharRd(); //I2C总线读出字符
//不作应答
io_SDA = 1;
DELAY_50ns; //延时0.05us
I2cBus_Ack(); //I2C总线应答符
I2cBus_Stop(); //I2C总线终止位
break;
} //读操作
return (uc2);
} //CAT1161读操作
//##################################################################
//CAT1161写操作
//入口; ui_Adr 地址
// ucp_Data 需写入的数据
//出口:
//通讯池:
//功能: 写入一个数据
//用法:
void g_CAT1161_Write(uint ui_Adr, uchar uc_Data) reentrant //CAT1161写操作
{
uchar uc1;
//扇区写操作
// 操作时间限制在10ms
for (uc1 = 0; uc1 < 250; uc1 ++)
{
//起始位
I2cBus_Start(); //I2C总线起始位
//I2C总线写入字符
// 寻址码写操作 高位地址
I2cBus_CharWr(b10100000 + ( ( * ( (uchar * ) & ui_Adr + 0) & b00000111) << 1) ); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
//存储低位地址
I2cBus_CharWr( * ( (uchar * ) & ui_Adr + 1) ); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
I2cBus_CharWr(uc_Data); //I2C总线写入字符
//从器件忙 操作失败
if (gb_Slave_Busy == 1)
continue;
I2cBus_Stop(); //I2C总线终止位
break;
} //扇区写操作
} //CAT1161写操作
这帖子在ZLG版块发表过,基本没人回应,不知是否发错了位置。
帖子写的乱糟糟的,请见谅! |