采用CSL调试C5509A的I2C小结 | | 作者:redbat_2… **来源:redbat_228 点击数:805 更新时间:2011-7-21 [url=][/url] | 两天在用CSL调试I2C总线接口的EEPROM,型号为24LC01。但是始终读写总是失败。以前在配置AIC23的时候,曾用过I2C。那时是根据瑞泰的程序修改的,但是程序运行不稳定,有时会出现无法配置的情况。这次比较有时间,对这个问题仔细研究了一下。
现在已经解决了,写了篇总结,以供参考。
由于我是从主板上引线到EEPROM板子的,所以开始怀疑是信号频率过高。测试波形,发现根本没有波形输出。降低5509A的主频,降低I2C总线的频率。经过N次尝试,终于能够正确读取数据了。测试波形,发现上升沿不是很陡峭,把I2C总线的上拉电阻由10k修改为了2.2k。这样上升沿足够陡峭了(至少确定该上升沿足够满足400k的频率了)。
恢复5509A的主频,提高I2C总线频率,读写还是失败。测试波形,仍然没有输出。在网上找到了一篇C5509A的I2C模块的应用文档(见参考文献),里面有读写EEPROM的例子。根据那个例子修改,读写仍然失败,现象依旧。
进一步搜索,发现有不少人碰到了类似的问题。最后,在TI的e2e社区找到了问题的所在(网址见参考文献)。原来是CSL中的I2C_setup函数有问题。摘取其中的解决方法如下:
I2C_FSET(I2CSTR,BB,0x1); /* Writing a 1 to BB Bus busy bit is supposed to clear it*/
/* Initializes I2C registers using initialization structure */
I2C_setup(&Init);
/* Need to calcualte I2CCLKL & I2CCLKH manually has functionnality not fully miplmented in CSL*/
I2C_RSET(I2CCLKL,220); /* Clock Divider Low register */
I2C_RSET(I2CCLKH,220); /* Clock Divider High register */
也就是在配置I2C模块之前,需要把I2CSTR寄存器中的BB位置1。同时,在待用完毕I2C_setup函数后,再重新配置一下I2CCLKL和I2CCLKH寄存器。
顺藤摸瓜,找到了CSL中的源文件,看到其中I2C_setup函数的代码如下:
void I2C_setup(I2C_Setup *Init) {
int old_intm;
Uint16 IPSC_calc;
old_intm = IRQ_globalDisable();
I2C_RSET(I2CMDR,I2C_I2CMDR_RMK(Init->free,0,0,0,1,1,Init->addrmode,0,Init->dlb,1,0,0,Init->bitbyte));
/* set own address */
I2C_RSET(I2COAR,Init->ownaddr); /* if slave, need to specify own address */
/* calculating the IPSC value */
IPSC_calc = (Init->sysinclock)/12; /* must correct rounding issue */
I2C_RSET(I2CPSC,IPSC_calc);
/* calculating the ICCLKL and ICCLKH register values */
I2C_RSET(I2CCLKL,15);
I2C_RSET(I2CCLKH,15);
IRQ_globalRestore(old_intm);
} /* end of init */
分析上面的程序,在计算I2C总线的频率时,出现了错误:因为I2C总线的频率主要由I2CPSC、I2CCLKL和I2CCLKH寄存器共同决定的。在程序中,根本就没有去查询I2C_Setup结构体中rate变量,只是查询了系统时钟,然后给I2CPSC寄存器赋值,而给I2CCLKL和I2CCLKH寄存器赋了固定值15。这无**确完成I2C时钟的配置。
打算重新编写这个函数。假设,input频率单位为MHz,I2C总线频率为kHz,则I2C总线频率的计算公式为:
module clock * 1000
master clock=-------------------------------------------------
[( ICCL+d )+( ICCH+d )]* (IPSC+1)
令ICCL = ICCH,则得到公式为:
input clock * 1000
master clock=------------------------------------------
2 * ( ICC+d ) *(IPSC+1)
根据上面的分析,重新编写了I2C_setup函数,如下:
void myI2C_setup(I2C_Setup * Init)
{
int old_intm;
Uint16 ICC_calc;
old_intm = IRQ_globalDisable();
I2C_RSET(I2CMDR,0); // reset I2C
// Set prescaler to generate module clock
// I2C input clock
// module clock=-------------------- , d=5
// ( IPSC+1 )
//
I2C_FSET(I2CSTR,BB,0x1); /* Writing a 1 to BB Bus busy bit is supposed to clear it*/
/* calculating the IPSC value */
I2C_RSET(I2CPSC,11);
// Set I2CCLKL & I2CCLKH to generate master clock
ICC_calc = (Init->sysinclock)/12;
ICC_calc = ICC_calc * 1000/2/(Init->rate);
ICC_calc = ICC_calc - 5;
I2C_RSET(I2CCLKL,ICC_calc); // 100kHz
I2C_RSET(I2CCLKH,ICC_calc);
/* set own address */
I2C_RSET(I2COAR,Init->ownaddr); /* if slave, need to specify own address */
//I2C模块复位,设置为主设备发送模式
I2C_RSET(I2CMDR,I2C_I2CMDR_RMK(Init->free,0,0,0,1,1,Init->addrmode,0,Init->dlb,1,0,0,Init->bitbyte));
}
通过测试,该函数能够成功用于EEPROM和AIC23的读写测试中。
此外,在采用byte write方式向EEPROM中连续写入数据时,注意在两次写入之间添加一个延时程序,否则会造成写入失败。
原文链接:http://www.61ic.com/Article/C5000/C55X/201107/36005.html |
|