IIC EEPROM读取解析
1. 编译错误处理(这里可以忽略)
在解压包解压了程序后,直接编译,出现如下错误。
*** WARNING L14: INCOMPATIBLE MEMORY MODEL
MODULE: .EZUSB.LIB (RESUME)
MODEL: SMALL
*** WARNING L14: INCOMPATIBLE MEMORY MODEL
MODULE: .EZUSB.LIB (DISCON)
MODEL: SMALL
*** WARNING L14: INCOMPATIBLE MEMORY MODEL
MODULE: .EZUSB.LIB (EZREGS)
MODEL: SMALL
*** WARNING L14: INCOMPATIBLE MEMORY MODEL
MODULE: .EZUSB.LIB (GET_STRD)
MODEL: SMALL
*** ERROR L102: EXTERNAL ATTRIBUTE MISMATCH
SYMBOL: PSTRINGDSCR
MODULE: .EZUSB.LIB (GET_STRD)
*** WARNING L14: INCOMPATIBLE MEMORY MODEL
MODULE: .EZUSB.LIB (DELAY)
MODEL: SMALL
*** ERROR L107: ADDRESS SPACE OVERFLOW
SPACE: CODE
SEGMENT: ?C_INITSEG
LENGTH: 16BFH
*** ERROR L107: ADDRESS SPACE OVERFLOW
SPACE: CODE
SEGMENT: ?C_INITSEG
LENGTH: 16BFH
*** ERROR L120: CONTENT BELONGS TO ERRONEOUS SEGMENT
SEGMENT: ?C_INITSEG
MODULE: periph.obj (PERIPH)
*** ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL
SYMBOL: PSTRINGDSCR
MODULE: .EZUSB.LIB (GET_STRD)
ADDRESS: 0B27H
*** ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL
SYMBOL: PSTRINGDSCR
MODULE: .EZUSB.LIB (GET_STRD)
ADDRESS: 0B29H
*** ERROR L120: CONTENT BELONGS TO ERRONEOUS SEGMENT
SEGMENT: ?C_INITSEG
MODULE: firmware.obj (FIRMWARE)
*** ERROR L119: REFERENCE MADE TO ERRONEOUS SEGMENT
SEGMENT: ?C_C51STARTUP
MODULE: E:SOFTWAREINSTALLPROJECTKEIL_FOR_51C51LIBC51L.LIB (?C_INIT)
ADDRESS: 0838H
*** ERROR L120: CONTENT BELONGS TO ERRONEOUS SEGMENT
SEGMENT: ?C_INITSEG
MODULE: E:SOFTWAREINSTALLPROJECTKEIL_FOR_51C51LIBC51L.LIB (?C_INIT)
面对错误,首先是百度了下,甚至还FQgoogle,好多说是keil为不完全版本,只能编译2kB的程序,超出会报错overflow,给出的方案是
方案一:下载完整版keil,重装试一下。
方案二:对图 1中的箭头位置进行修改,在这里看出,方案一不适用。
图 1 修改配置
按照方案二试着修改(各种实验修改)配置后,warming消除了,但是对error没有什么卵用。后来发现图 2中所示的Device没有选对。
图 2 选择设备
修改图 2中的设备,选为CY7C68013×××-×后,还要在图 2中的可选项Use Extended Linker(LX51) instead of BL51选中,这样就可以编译通过了。
但是吧,这个虽然编译通过了,但是程序好像是错误的。因为通过0xED vendor command进行读取EEPROM的数据时,提示错误!
我之前用的是历程中已经解压的程序,后来讲例程中的压缩包程序解压后,编译直接通过,上面两处错误(设备和选项)没有改,下进了CY7C68013A中后,通过0xED vendor command进行读取EEPROM时,会有数据返回,虽然返回的不是预期的,再查证。
2. 程序解析
首先初始化:TD_init();
然后是设备描述符的相关处理;
接着是循环执行:TD_Poll()函数,在这个函数里,往IIC接口的EEPROM里面写入数据(写入是一次写一个),同时在EEPOM里面读出数据(读出是一次将写入的3个同时读出),并存入到寄存器中。
在循环函数中,检测控制传输令牌包的到来,一旦接收到令牌包,就会将存放IIC读书数据的寄存器中的数传到主机。
3. 运行错误处理
这个程序可以直接用。并且将1错误处理中的device改为CY7C68013和option选上了。
其实PDF(CE63180)文档里面已经写得非常详细。
就是在上电之前,将EEPROM的跳线帽拔下来,不让他在EEPROM中启动,这样PC才可以识别到设备,上电后,下载程序前将跳线帽插上,这样在下载了程序后,会自动的往EEPROM中写数据。
在PC的上位机软件中做如图 3配置,点击Vend Req按钮,即可读取程序自动写入EEPROM中的数据。但是不知道是没有写入,还是读取不成功,返回来的数据都是00,00,00 ,显然,这是不正确的。经过示波器测试IIC的数字信号,发现发出的都是10100000。再结合IIC的通信协议,发现这是发送的IIC 芯片的地址。读出来的数据时00,00,00是因为程序是按照官方的开发板写的,但是淘宝的开发板和官方的有点区别。图 3和图 4对比所示。由两个不同IC(24LC00和24L128)的datasheet可以看出,他们IIC地址的前4为均为1010,后面三位由电平决定。图 3中A2,A1,A0均为0,所以地址为1010_0000(0xA0)。而淘宝开发板的A0被拉高,所以地址为1010_0010(0xA2)。因为用的是淘宝的开发板,所以这里要修改。
在程序中Periph.c文件中有一个宏定义:#define EEPROM_ADDR 0x50,这个宏在TD_init()函数中赋值给了IIC地址:I2C_Addr = EEPROM_ADDR;
因为在写地址时,先把地址左移一位(I2DAT = I2C_Addr << 1),所以这里的宏定义为地址的右移一位值:0x50 = 0xA0 >> 1。
由于使用了淘宝货,这里没有改的话,就不能往EEPROM中写入数据,也不能读取,所以返回来的是00,00,00,如图 5。这里要在程序中将宏的值改为EEPROM地址的右移一位值:0x51 = 0xA2 >> 1。
图 3 官方开发板原理图
图 4 淘宝开发板原理图
图 5 上位机的配置
进行了如上修改之后,再次烧录,读取。发现读出来的数据不正确如图 6所示,用示波器测试,发现现在不只是发送0xA0那么简单了,具体是什么也没有细究。
接下来继续看程序。在图 7所示的TD_init()中的注释引起了注意,DB_Addr = 1 if the EEPROM is double byte addressing(双字节寻址)
图 6 修改地址后的读取值
图 7 TD_init()函数
将TD_init()中的DB_Addr = 0改为DB_Addr = 1后,下载读取,可以实现将TD_Poll()中写入EEPROM中的数据读出来并返回到host。如图 8所示
图 8 读取正确数据
通过此实验可以证明,开发板上用的ATMEL的24C128 EEPROM是双字节寻址。下了数据手册,看数据手册,在第7页的Device addressing中,如图 9所示,但是这里的8bit是device addressing,是IIC的地址,不是我们写入和读取的存储空间的地址。所以不是看这里。
图 9 datasheet 的描述
接着往下看,在第8页和第9页中,写入时序和读取时序分别如图 10和图 11所示,可以明确看出,前面方框中的device address与上面的描述对应,椭圆中的word address分为了1st,2nd两个字节byte,为double byte addressing(双字节寻址),可以与24LC00 datasheet中的时序图作对比,发现它是单字节寻址,因此官方例程中的DB_Addr = 0。完美解决。睡
图 10 写入时序
图 11 读取时序
此问题的解决,也是通过FQ,在google搜索中,搜到的别人的答案。连接为:https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=17590
在连接中有启发的回答为图 12所示
图 12 有启示的回答