查看: 1930|回复: 0
打印 上一主题 下一主题

采用CSL调试C5509A的I2C小结

[复制链接]
跳转到指定楼层
沙发
发表于 2016-4-3 21:59:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这两天在用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中连续写入数据时,注意在两次写入之间添加一个延时程序,否则会造成写入失败。



备注:总结的一些知识点也放在这里,供参考。

1、关于24LC01知识点

24LC01共有128x8 bits=1k bits存储空间。关于24LC01、24LC02、24LC04、24LC08、24LC16的命名规则:其中,01、02、04、08、16表示存储空间为1k、2k、4k、8k、16k。

24LC01的写有两种方式:byte write和page write。前者只能写入一个字节数据,后者最多可以写入8个字节数据。读有三种方式:Current Address Read、Random Read、Sequential Read。第一种读取当前地址数据,第二种读取某个地址数据,第三种可以连续读取多个数据。在每次读写操作后,24LC01内部的地址会自动加一,连续读取写入多个数据就是基于这个原理。

关于slave address,包括control code和block select bits两部分。对于24LC01来讲,block select bits可以忽略。其slave address为0x50。

2、关于CSL中I2C模块函数

主要用到的函数包括:I2C_setup、I2C_read和I2C_write。

1) 关于I2C_setup,下面代码为I2C模块的相应配置信息。

I2C_Setup Setup = {

0, /* 7 bit address mode */

0x0000, /* own address */

144, /* clkout value (Mhz) */

400, /* a number between 10 and 400 */

0, /* 8 bits/byte to be received or transmitted */

0, /* DLB mode off */

1 /* FREE mode on */

};

2) 关于I2C_read和I2C_write,注意其中的模式选择,共有以下三种模式:

1) S-A-D..(n)..D-P

2) S-A-D..(n)..D (repeat n times)

3) S-A-D-D-D..... (continuous)

其中S表示start condition,A表示address,D表示data,P表示stop。模式1用于n个数据操作,最后会有stop信号。模式2一用于n个数据操作,但最后没有stop信号。模式3用于多个数据操作,也没有stop信号。

参考文献:

1、Programming the TMS320VC5503/C5506/C5507/C5509/C5509A I2C Peripheral (SPRA785A)

2、TMS320C55x Chip Support Library API Reference Guide(SPRU433J)

3、24LC01数据手册

4、TMS320VC5501/5502/5503/5507/5509 DSP Inter-Integrated Circuit (I2C) Module Reference Guide (SPRU146D)。

5、http://

e2e.ti.com/support/dsp/tms320c5000_power-efficient_dsps/f/109/p/11040/43000.aspx
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表