IIC加载以及存在的问题---lattice XO3
XO2/XO3系列使用IIC进行在线升级的时候使用的I2C Embedded(在diamond软件安装目录下可以找到在线升级的C代码,<install_path>\embedded_source\i2cembedded\src\i2cem),IIC总线的信号是漏极开路的,所以默认情况下是,信号线是低电平,需要加上啦电阻,使其默认是高电平。IIC总线上建议不要挂太多的器件,建议只挂我们一个CPLD,因为信号质量无法保证。为了能够使用IIC总线进行在线加载(program),I2C_PORT必须要设置为ENABLE,特别是使用2B线,用PC烧写的时候(默认是diable,3.2以前的版本是直接软件里面改为ENABLE就可以了,但是3.2以后的版本设置相对复杂点),在diamond3.2及以前版本中设置,如下截图。
diamond3.2以后的版本如何使能I2C_PORT,先看看用上述操作的结果,如下图,报错了,呵呵
那么我们要加入EFB模块,而且wb_clk_i的频率要>=3MHZ,而且还有把sda scl引到顶层。调用EFB,Primary Configuration和User Flash Memory一定都要选上,如下图
代码中例化如下
/*******************************************************************
*******************************************************************/
module control(
inout wire scl,
inout wire sda
);
wire osc_clk;
defparam OSCH_inst.NOM_FREQ = "7.00";
OSCH OSCH_inst( .STDBY(1'b0), // 0=Enabled, 1=Disabled
.OSC (osc_clk),
.SEDSTDBY()
);
efb efb_inst(.wb_clk_i( osc_clk),
.i2c1_scl( scl ), //要把IIC的脚接到顶层
.i2c1_sda( sda )
/* .wb_rst_i( ),
.wb_cyc_i( ),
.wb_stb_i( ),
.wb_we_i( ),
.wb_adr_i( ),
.wb_dat_i( ),
.wb_dat_o( ),
.wb_ack_o( ),
.i2c1_irqo( ),
.wbc_ufm_irq( )*/
);
endmodule
/*******************************************************************
*******************************************************************/
不选Primary Configuration,IIC脚根本就无法访问,也就无法使能,同时MAP的时候也会报上诉错误,如下图没有i2c1_sda i2c1_scl
不选User Flash Memory,wb_clk_i无法给入,同时MAP的时候也会报上诉错误,如下图没有i2c1_sda i2c1_scl
1.跑一遍产生.JED
2按照ProgrammingToolsUserGuide38第128页,继续往下跑,设置流程截图如下
随便解释一下.iea是指令 .ied是数据,给出的参考嵌入式代码不是lattice自己人写的,是lattice找人开发的,所以有BUG的话是没办法解决的,只能避开。所以建议客户不要用传.iea .ied的参考代码。客户自己写C代码,只传要加载的数据,这样出了问题客户自己可控,就不用找我们麻烦。
在安装目录C:\lscc\diamond\3.8_x64\embedded_source\i2cembedded\src下,有两份IIC加载的C代码,这个是客户根据需求选择的
调试过程
感觉XO3LF空白芯片(擦除后和买回来没试用过的芯片)没法在线加载,调了好几天没有几把用,XO2我之前在另外一个部门调试是OK的。调试的思路和过程如下
首先检查客户的硬件PROGRAMN和SN管脚都是已经拉高了,这个是因为加载时有优先级的,而且空白芯片SPI IIC JTAG使能都是打开的,假如那两个脚没有拉高进入他们的加载状态,IIC优先级比较低级无法进入IIC在线升级的状态了,优先级JTAG>SPI>IIC。
然后测试了以下几种情况
1.例化EFB,把IIC脚拉到顶层,通过jtag方式烧写到芯片,然后用CPU对CPLD
进行在线升级是可以的,具体操作流程如下
/**********************用JTAG烧写的代码***************/
module control(
inout wire scl,
inout wire sda
);
wire osc_clk;
defparam OSCH_inst.NOM_FREQ = "7.00";
OSCH OSCH_inst( .STDBY(1'b0), // 0=Enabled, 1=Disabled
.OSC (osc_clk),
.SEDSTDBY()
);
efb efb_inst(.wb_clk_i( osc_clk),
.i2c1_scl( scl ),
.i2c1_sda( sda )
);
endmodule
/**********************用JTAG烧写的代码***************/
烧写完毕之后,用CPU对CPLD进行在线升级是没有问题的,作为对比我读取了Feature Rows的值
首先先把芯片jed读回来
然后在用软件读取读回来的JED的feature rows的值,操作如下
跳出来一个界面,操作如下
读回来的信息如下
default是默认值,IIC_PORT默认值是打开的(Enable),也就是说FILE_VALUE=0,说明是打开的,当擦除之后FILE_VALUE的所有值应该与default所有值相同。
/**********************用JTAG烧写的代码***************/
module control(
output wire led
);
assign led=1;
endmodule
/**********************用JTAG烧写的代码***************/
烧写流程如上,现仅将回来的feature rows的值作为对比,如下图
发现读回来的值是不一样的file value=1,这个应该是关掉了IIC_PORT,但是默认的情况不是打开的吗?是什么操作是它被关掉的呢?然后查了手册,手册写的默认值如下图,感觉好奇葩file value=1不是关掉IIC_PORT吗?怎么手册给出来的值是file value=1,HW DEFAULT中确是ENBALE?
疑问自答:1.读回来的file value=1是关掉IIC_PORT的意思,芯片默认确实是打开的,但是软件默认是关闭的IIC_PORT,而且又下载了一段不加EFB去打开IIC_PORT的代码,所以IIC_PORT自然而然就关掉了,所有IIC无法在线升级就可以理解了,因为IIC_PORT被关掉了啊。
2.写文档的人瞎搞,截出来的图不是空白芯片的值,只是一个feature rows的例子而已。
3.尝试了用jtag对芯片进行擦除操作,再进行在线加载,发现也是无法在线加载的,表现为没有发响应,iic没有通信上(手册上说这种方式可以实现在线升级的,草)。操作流程如下:
擦除之后用jtag回读回来的feature rows的值如下
通过对比可以发现,FILE Value=0的时候且在有程序的前提下,是可以实现在线加载的。但是这个官网数据手册说的不一致,数据手册说空白芯片和擦除的情况下是可以进行在线加载的。所以得继续查问题______————————________
经过对比调试发现,有程序在芯片时,program=1(diable),IIC_PORT=0(enable);空白芯片时program=0(enable), IIC_PORT=0(enable),如下图。
所以尝试测试在有程序的情况下,把Program改为enable,假如修改为把Program改为enable之后,无法实现在线升级了,那么问题就明了了,下图是如何把Program改为enable。
修改了之后发现确实无法升级了,那么是不是可以说明是Program为enable使得无法进行在线升级呢?为了确保万无一失,我们再进行一个测试。在芯片没有程序的情况下,将Program改为disable。这个怎么改呢?有点学问。首先你不能烧程序进去,因为烧了程序进去就不是空白芯片了,其次你还要修改program的值,而且只改一位。不幸中的万幸,软件可以进行只加载Feature row,也就是说我可以通过通过软件生成带程序的而且program为disable的JED,然后加载JED的时候只进行feature row的加载,不加载用户逻辑。操作如下
操作完上述过程相当于空白芯片,Program改为disable,嵌入式系统那边跑起来,惊奇发现测试灯亮了,亮了(用于测试升级的代码),妈呀成功了。
以上说明什么问题,lattice给的升级参考嵌入式代码有问题,有BUG。为什么这样说呢?因为我们用2B线测试过,不管在什么情况下,都是可以program的,说明不管Program是disabe还是enable,不管是不是空白芯片,都是可以program的。唯一的不同就是一个通过C代码配合CPU去program,一个是通过线去加载,硬件完全一样。
通过上述可以明显知道是lattice提供的C代码有bug,那么在线升级的时候怎么解决呢?做了上面的测试,思路很明显出来了。生成两份.ied .iea,第一份做事情是将空白芯片的Program改为disable,第二份做的事情是加载用户逻辑,当然客户嵌入式那边也要做两份Makefile。为了修复这个BUG,如下做出详细操作流程。
生成第一份.ied .iea,目的Program改为disable
做好下图设置之后先生成.jed
下面这一步非常重要,一定要选对,选只加载feature的值,这就相当于只把program改为diable而不加载用户程序,然后狂点next就可以生成了。
生成第二份.ied .iea,目的是生成加载的用户程序,流程在最开始就说了,不再累赘。
用两份IED IEA,可以实现空白芯片的加载,但是在客户多次尝试之后发现新的问题:芯片里面有程序的时候,用用两份IED IEA是无法在线加载的!!!!!!!现在出现了两种情况:有程序的时候,只能用有用户数据的IEA IED去升级,没有程序的时候需要用两份IEA IED去升级。叫客户将就着用,但是客户死活不肯。接下来的解决思路:通过CPU发读Read FEABITs (0xFB)指令,把PROGRAMN的值读回来,当PROGRAMN=1,说明是有程序(有feature row)在芯片的,这时候让CPU去加载两份IEA IED;当PROGRAMN=0,说明是没有程序(擦除过或者是出厂的空白芯片)在芯片的,这时候让CPU只加载一份包含用户逻辑数据的IEA IED。这个方法就需要用户去写C,试了好几天大华也没写出来。另辟蹊径,看了各种手册,发现有程序(有feature row)的时候,写两份IEA IED无法实现在线加载,原因是加载第一份的时候feature row已经被写过一次,在不擦除去情况下,再去写feature row就会导致芯片hold死,从而导致芯片升级不成功。那么解决思路就出来,无论哪种情况,都用两份IEA IED实现在线加载,但是在加载第一份IEA IED(仅仅包含feature row的值)之前,先erase一次feature row,问题就可以解决了。但是问题又来了,erase feature row怎么操作呢?是否有这个指令让cpu指erase feature row。幸运的是,在文档中给出了这个指令。
仔细想想这个方法还是不够简洁,既然可以通过cpu去发erase feature row,那么软件生成的时候应该也有对应的选型,然后在软件中找到对应的,感觉像自己想要的选型,进行尝试。非常有意思,一把就试成功,不管有没有程序,不管是否断电,在生成第一份IEA IED的时候,选择I2C Erase Program Verify Feature一切搞定(因为这个选项包含erase feature row),选项如下截图。
总结IIC升级步骤:
(1)调用EFB将IIC_PORT口打开
(2)生成第一份IEA IED,目的disable programn,而且应该选择I2C Erase Program Verify Feature(这选项会更新Feature Row的值的),仅仅更新Feature Row
(3)生成第二份IEA IED,目的生成用户数据,而且应该选择I2C Erase,Program,Verify(这选项是不会更新Feature Row的值的),仅仅更新用户逻辑
结束语:干这行的,一定要有怀疑的精神,怀疑的不仅仅是客户芯片厂家也是完全可能出现问题的,厂家的bug也是正常的,厂家没有BUG,FAE就没有存在的意义了。上述发现的BUG不是芯片本身的bug,是提供的参考C代码的bug.