1 引言
自边界扫描技术问世以来,国际上一些公司均推出了各自的支持边界扫描的测试设备,可以对被测设备的边界扫描机制进行校验,并对被测设备的静态故障进行测试。测试结果以逻辑真值表的形式提供,不具备对被测设备进行故障诊断定位的能力,并且其测试软件以英文DOS为平台,操作较为不便,不适宜在国内使用 [1]。国内从90年代中期开始研究边界扫描技术,取得了一定的成果,但多是对完全BS (boundary scan)器件的边界扫描测试,对由非BS器件组成的逻辑簇的测试还鲜见报道。本文所介绍的基于边界扫描的逻辑簇测试诊断软件以Borland C++ Builder为开发工具,能够自动产生逻辑簇的串行测试矢量,准确进行故障定位,并附加有边界扫描结构完备性测试功能模块,提高了测试可靠性。
2 逻辑簇测试诊断软件设计
一个边界扫描测试诊断过程可以简述为:首先输入测试矩阵进行激励,然后输出响应矩阵,最后通过分析响应矩阵就可达到对故障进行诊断定位的目的。所以说,故障诊断问题就集中在测试矩阵的构造、列测试向量的并行加载、列响应向量的并行采集和响应矩阵的分析上。我们在进行软件设计时,利用并行测试矢量描述与簇描述文件来构造完备的测试矩阵,将其以串行扫描方式由边界扫描器件的TDI经BS链路串行移位送到与逻辑簇相连的相应BSC,然后通过TMS发送测试控制命令,经TAP控制器控制BSC完成测试码的并行加载和响应码的并行采集。测试响应码则经BS链路串行移位从边界扫描器件的TDO送到测试机处理得到响应矩阵,最后通过对响应矩阵的分析来进行逻辑簇电路故障的诊断定位。
2.1 软件设计流程图
逻辑簇测试的程序流程图如图1所示,其中各步骤的具体作用如下。

边界扫描信息数据选择与设置:设置PCB板边界扫描链的组成、选择PCB板的网络表、选择各BS器件的BSDL信息、选择被测逻辑簇描述文件、输入其并行测试矢量描述文件。
编译信息:从BS器件信息数据库中读取各芯片的边界扫描长度、指令码、边界扫描单元总数、逻辑簇与BS器件互连网络总数及各网络的组成,并根据 PCB板的BS链组成给各BSC从最靠近TDO端开始编排序号,然后译出加载诊断矩阵和采集响应结果的对应BSC序号。
生成测试矩阵:根据逻辑簇与BS器件互连网络总数及各网络的组成,结合逻辑簇的并行测试矢量或簇描述文件,利用测试生成算法生成测试矢量集,构成测试矩阵。
边界扫描结构完备性检查:进行边界扫描寄存器、指令寄存器等寄存器的功能测试和各TAP端口信号故障测试。
TAP控制器复位并控制其进入移位指令寄存器状态:在测试时钟的上升沿发送“11111”到TMS引脚,扫描链所有芯片TAP控制器处于复位状态。然后再次发送“01100”到TMS引脚,TAP控制器进入移位指令寄存器状态。
选择边界扫描寄存器连接在扫描链上:从TDI 引脚发送各芯片的SAMPLE指令至各芯片的指令寄存器。在测试时钟的上升沿发送 “11100”到TMS端,各芯片选择边界扫描寄存器连接在扫描链上, TAP控制器进入移位数据寄存器状态。
测试矢量输入扫描链并串行移位到相应BSC:读取测试矢量集中的列向量送入对应边界扫描单元(即逻辑簇的虚拟输入端)等待加载。
向扫描链各BS器件输入对应的EXTEST指令:在测试时钟的上升沿发送“111100”至TMS端,TAP控制器进入移位指令寄存器状态,发送各芯片 EXTEST指令至各芯片的指令寄存器。发送“111100”至TMS端,通过各芯片输出端口上的BSC将数据加载到网络,TAP控制器处于移位指令寄存器状态。
扫描链各BS器件输入对应的SAMPIE指令:发送各芯片的SAMPLE指令至指令寄存器。在测试时钟的上升沿发送“11100”至TMS端,各芯片从互连网络上获取数据并存入输入端口的BSC中,各芯片TAP控制器进入移位数据寄存器状态。
从边界扫描链TDO端串行输出响应数据并存储:连续发送N(BSC总数)个测试时钟到TCK端,并在每个测试时钟的下降沿采集TDO引脚移出的数据,提取并保存各逻辑簇虚拟输出端对应的响应数据构成响应向量。
组成响应矩阵分析测试结果:将所有的响应向量组成响应矩阵,与正确测试响应相比较和分析,判断逻辑簇是否存在故障。
2.2 逻辑簇测试的设置
在进行边界扫描测试时,首先要对测试矢量自动生成所需的若干信息进行设置。对于BS器件之间的互连测试,其设置只需填写扫描链信息和选择网络表文件。而对逻辑簇的测试因为涉及到簇的定义及针对其功能的并行测试矢量,设置所需信息相对复杂,包括有:
⑴扫描链路的组成芯片、各芯片的边界扫描指令与其BSC单元信息;
⑵被测电路板的网络表文件*.edf;
⑶逻辑簇的并行测试矢量描述文件*.vdf;
⑷簇描述文件*.cld。

本软件逻辑簇设置界面如图2所示。扫描链路设置要依次选择或填写组成扫描链的芯片总数、芯片序号(第*片)、芯片标称(网络表中芯片的名称 U1、U2等)以及芯片的具体名称和相关边界扫描信息。芯片的边界扫描相关信息是一个可以编辑、增添、修改信息的数据库,选择了芯片名称即可调用其数据库信息。“逻辑簇测试选择”一栏用来选择被测的是单个非BS器件还是由非BS器件组成的簇,对于单个非BS器件,只需填写器件标称,而对于簇测试,还需编写一个定义簇的输入输出、端口名称的簇描述.cld(cluster description)文件。另外,它们的并行测试矢量文件.vdf(vector description file)也需由用户编写输入。cld与vdf文件都是自行设计的有一定语法规范的的文件编辑格式,简捷易用,用户只需了解逻辑簇的组成和功能就可以容易地编辑。
逻辑簇测试所有信息选择填写完成后,点击 “确定”开始测试或选择“保存设置”、“载入设置”等命令。
3 逻辑簇测试实例验证
3.1 试验板结构
为研制基于边界扫描的逻辑簇测试诊断软件,我们在一块带有示范性的试验板上对某逻辑簇进行了测试实例验证。被测逻辑簇为试验板的一部分,其电路如图3所示。试验板采用了边界扫描测试性设计技术,逻辑簇器件74LS04(U 5)的输入输出管脚均与BS器件U1、U 2(Altera公司的EPM7128SL84)相连,因而可以把U 1、U2的边界扫描单元作为其虚拟测试点,实现了可观性、控制性。开关K1用来控制U1与U5 连线的通断,以模拟U5的故障情况。

3.2 测试矢量的加载
本试验中,74LS04的6个输入管脚1、3、5、 9、11、13与U1的63、64、65、67、68、69管脚相连,其对应的输出型BSC序号为53、56、59、65、 71、74;74LS04的6个输出管脚2、4、6、8、10、12与U 2的63、64、65、67、68、69管脚相连,其对应的输入型BSC序号为72、69、63、57、54、51。
74LS04是一个简单的非逻辑,输入管脚1、3、 5、9、11、13与输出管脚2、4、6、8、10、12对应为反,对它的功能测试比较简单,且故障能够定位到它与U1、U2的连线。其测试矢量应先给各输入端赋值0,输出端应该输出1;再给各输入端赋值1,输出端应该输出0。如果某一对端口不能完成此测试,而其它端口可以,则说明这一对端口与U1 或U2的连线有故障;若全部逻辑不符,则说明芯片 74LS04出故障。首先按照并行测试矢量文件VDF的语法格式,根据以上逻辑编写出逻辑簇的并行测试矢量文件(此处略)。
为利用U1的BSC单元把测试矢量加载至U5,首先要由网络表和BSDL编译函数把并行测试矢量加载到与U 5相连的U1对应管脚的输出型BSC单元。U5的 I/O管脚是三态管脚,其每个管脚对应的BSC单元控制必须赋输出允许值“1”,经过软件的网络表和BSDL 编译分析,最终从TDI输入U1的第一组串行测试矢量为“111…0110110111110111110110…111”,这样,序号为53、56、59、65、71、74的U1的BSC单元赋值为0,其余为1。第二组串行测试矢量为“111…111”,即全1。
3.3 测试响应的输出
在指令移位状态下输入EXTEST指令“0000000000”,U 1将测试矢量加到U5的输入端,U5完成各输入端逻辑非的功能,输出端得到对激励的响应。同时U2捕获U5输出管脚的数据,送入U 2对应管脚的输入型BSC单元。控制TMS,转换至数据移位状态,串行输出U2的288个BSC单元值,对第一组串行测试矢量的输出响应如图4(a)。经过对TDO值的分析编译,从中提取出U 5输出管脚2、4、6、8、10、12对应的值为全“1”,说明第一组测试无故障。用同样的控制过程得到TDO对第二组串行测试矢量的输出响应如图4(b)。
同样对TDO值进行分析编译,从中提取出U5输出管脚2、4、6、8、10、12对应的值为全“0”,第二组测试亦无故障。软件输出互连网络完好的结果提示。

为模拟逻辑簇的故障情况,用开关K 1断开U1与U5的两条连线,重复以上测试过程,通过对测试矢量和测试响应的对比分析,可以准确地将故障定位到断开的连线上。另外,逻辑簇测试前需执行边界扫描结构完备性测试程序,具体过程请参见文献[2]。
4 结束语
本文详细介绍了基于边界扫描的逻辑簇测试诊断软件的设计原理、流程图与应用,并通过测试实例初步验证了软件的有效性与可靠性。但由于逻辑簇的复杂不一、串/并行测试矢量相结合的工作方式,不可避免地会带来扫描链管理、器件隔离等诸多问题,它们在软件调试过程中也时有发生,如何解决这些问题我们将在后续工作中继续研究
易忽略的TAP控制器IRSHIFT->IREXIT1和DRSHIFT->DREXIT1的细节
该状态的跳变的同时,寄存器还将顺序移位一位。
这一点很容易忽略,测试设备应该在最后一位TDI输出的同时改变TMS,然后再输出TCK的脉冲。
同时,还需要注意,TCK的常态应该是低电平。1149.1规定了在TCK为低电平的时候,TAP状态应能够维持无限长时间,而高电平下的维持只是建议内容
jflash源代码阅读==
常常是板子出了问题就手足无措,常常要给板子上面信号的时候要用ADS写长长的程序(我用ARM)
常常看到Jflash的程序出错就只知道重起板子,于是我就常常想阅读一下Jflash的源代码
今天,我终于祭起长久不用的Source Insight,建立工程,开始阅读Jflash
所谓打蛇打七寸,读程序先读main
我就从main开始对jflash进行解剖
我读的代码是windows版本的,用VC进行编译,我想Linux版本的应该也差不多,就是要定义一个宏吧,这个问题暂且不关注,先关注程序本身
程序一开始就是一大堆没有注释的变量,也许我是才疏学浅的原因,我硬是看不懂那些变量是做什么用的,暂且跳过吧,先看后面的程序
#ifdef __windows__
//Test operating system, if WinNT or Win2000 then get device driver handle
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
HANDLE h;
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(h == INVALID_HANDLE_VALUE)
error_out("Couldn't access giveio device");
CloseHandle(h);
}
#endif
版权信息就不说了,下面就是检测giveio是否已经安装好了
如果没有安装好,就提示Couldn't access giveio device
接着调用test_port()函数,以寻找一个可以用并口
在分析test_port()之前,我们首先对并口编程先进行一些介绍
我们的PC机一般有三个并口,他们的IO地址范围通常是:
0x3bc-0x3be
0x378-0x37a
0x278-0x27a
在很多电脑里面,通常连接Jtag的并口是以0x378为基地址的并口
可以看到一个并口有三个IO地址,第一个是数据寄存器地址,第二个是控制寄存器地址,第三个是状态寄存器地址。
JTAG原理
上篇文章刚刚提到 test_logic_reset函数,这个函数是用来reset Jtag链的,继续分析之前,还是先让我们来了解JTAG的工作状况。为了测试我们的PCB板的方便,JTAG这个东西被搞了出来。如果想更多的了解 JTAG,大家可以去看看IEEE 1149.1的标准,如果只是和我一样,想了解一下的话,大家可以看看Mark Zwolinski著《VHDL数字系统设计》,电子工业出版社出版了他的中文版。
没一个JTAG兼容的元件都有一个共用的测试结构,这种结构基本单元如下:
1、测试存取端口
测试存取端口包括4个或5个为测试增加的引脚。这些引脚是:
TDI和TDO(测试数据输入和输出)。数据和指令通过扫描路径送至IC。没有办法从指令中区分数据,或者判断一系列位的目标是到达哪个特定的IC。因此,下面的引脚用来控制数据流向。
TMS(测试模式选择)。与TCK引脚一起,TMS引脚用来控制一个状态机以决定每位通过TDI到达目的地。
TCK(测试时钟)
TRST(测试复位),这是可选的异步复位信号,很多的JTAG电路中没有这个信号。
2、TAP控制器
TAP控制器是一个具有16个状态的状态机,它用来控制测试。状态机的输入是TCK和TMS,输出是其它寄存器的控制信号。下面链接是我在一个网站上找到的他的状态图,大家也可以在google的图片里面搜索tap controller,就可以搜索到这个状态图。
http://www.inaccessnetworks.com/ian/projects/ianjtag/jtag-intro/jtag-state-machine-large.png

通过这个图可以看出,TMS脚上保持5个时钟周期的高电平,会使得状态机从任何状态进入Test-Logic-Reset。TAP控制器发出的控制信号用来启动器件中的其它寄存器。这样,如果到达TDI的位序列合适,就将被送到指令寄存器或者特别的数据寄存器。
3、测试数据寄存器(Test Data Registers)
一个与边界扫描兼容的元件必须将其所有的输入和输出连接至扫描路径。一下描述的特殊单元用来实现扫描寄存器。另外,必须有一位的旁路寄存器,这样可以通过绕开元件的边界扫描寄存器来缩短扫描路径。另外还需要一些其他的寄存器,例如,一个IC可能需要一个标志寄存器,这个寄存器的内容可以通过扫描访问来确定 PCB板上是否装配了正确的IC。同样,我们可以通过边界扫描接口访问器件的内部扫描路径。某些可编程逻辑生产商允许使用边界扫描器件来对器件进行编程,因此,另一种可能的数据寄存器是配置寄存器。
4、指令寄存器(Instruction Register)
指令寄存器至少有2位,这依赖于实现的测试数目。它定义了测试数据寄存器的使用。指令寄存器还产生进一步的控制信号。
边界扫描单元有四种操作模式:
1、普通模式。一般的系统数据从In传输至OUT
2、扫描模式。shfiterDR选择SCAN_IN引脚,ClockDR提供扫描路径时钟。ShifterDR值由Tap控制器中相似的名称的状态得来。当TAP控制器处于状态capture-DR或者shifter-DR时,断言ClockDR
3、捕捉模式。ShiftDR选择In引脚,数据由ClockDR时钟送入扫描路径寄存器来对系统进行快照
4、更新模式。在捕捉或者扫描之后,数依据通过UpdateDR一个时钟沿从左边沿触发送至OUT。
test_logic_rest函数分析
好,这里说了这么多的JTAG,下面我们继续分析源代码, test_logic_reset的代码如下:
void test_logic_reset(void)
{
putp(1,1,IGNORE_PORT);// keep TMS set to 1 force a test logic reset
putp(1,1,IGNORE_PORT);// no matter where you are in the TAP controller
putp(1,1,IGNORE_PORT);
putp(1,1,IGNORE_PORT);
putp(1,1,IGNORE_PORT);
putp(1,1,IGNORE_PORT);
}
这个函数的目的是用来对JTAG逻辑进行重置的,函数调用了6个putp函数。
putp函数源代码如下:
int putp(int tdi, int tms, int rp)
{
int tdo = -1;
// TMS is D2, TDI is D1, and TCK is D0, so construct an output by creating a
// rising edge on TCK with TMS and TDI data set.
_outp(lpt_address, tms*4+tdi*2+8);// TCK low
_outp(lpt_address, tms*4+tdi*2+1+8);// TCK high
// if we want to read the port, set TCK low because TDO is sampled on the
// TCK falling edge.
if(rp == READ_PORT)
_outp(lpt_address, tms*4+tdi*2+8);// TCK low
if(rp == READ_PORT)
tdo = !((int)_inp(lpt_address + 1) >> 7);// get TDO data
这里的代码是使用并口做JTAG访问的代码,可以看出,这个函数是产生一次TCK脉冲,同时发送数据和接受数据的。tdo最后返回的是TDO的状态值,使用了一个!是因为前面说过最高位的逻辑是与信号线上相反的。知道的putp代码的作用,我们就可以看出来,test_logic_reset的作用是让 TMS保持6个高电平,前面说过,TMS 5个电平就会使得器件进入重置状态。
jtag_test()函数分析
接下来,jtag_test()函数被调用,我们再来对他进行分析
void jtag_test()
{
// set all devices into bypass mode as a safe instruction
pre_IRSCAN();
if (controller_scan_code(COT_BYPASS, READ_PORT, CONTINUE) != 0x1)
{
error_out("Jtag test failure. Check connections and power.\n");
}
post_IRSCAN();
printf("JTAG Test Passed\n");
}
首先, pre_IRSCAN()被调用, pre_IRSCAN()的代码如下:
void pre_IRSCAN()
{
putp(1,0,IGNORE_PORT);//Run-Test/Idle
putp(1,0,IGNORE_PORT);//Run-Test/Idle
putp(1,0,IGNORE_PORT);//Run-Test/Idle
putp(1,0,IGNORE_PORT);//Run-Test/Idle
putp(1,1,IGNORE_PORT);
putp(1,1,IGNORE_PORT);//select IR scan
putp(1,0,IGNORE_PORT);//capture IR
putp(1,0,IGNORE_PORT);//shift IR
}
可以看出来,TAP状态机从Run_test/IDL到Selet_DR-Scan到Select-IR-SCAN再进入Capture-IR,最后进入Shift-IR,从函数返回的时候,器件进入等待数据移位进入IR的状态
然后,controller_scan_code函数被调用,该函数则完成将一个BYPASS指令移进IR当中,然后为什么会在TDO上得到一个高电平我就不清楚了,可能这是对BYPASS命令的应答。然后Post_IRSCAN被调用,状态机返回到Run-Test/Idle模式
Jtag-test完成之后,就开始真正的flash烧写过程了
昨天分析到jtag_test了,今天继续往下看
char filename[MAX_IN_LENGTH];
if(argc >= 2)
strcpy(filename,argv[1]);
else
{
printf("enter file: ");
gets(filename);
}
程序接着检查了是否有指定文件名,如果没有,则获取文件名
test_logic_reset();
再次重置Jtag逻辑,使得系统进入可靠状态。
id_command();
执行id_command,该函数首先使TAP控制器进入ShiftIR状态,然后向IR中移入COT_IDCODE(0x1E)指令,然后使TAP控制器进入shiftDR状态,往TDI信号置1,将DR值移出来,与系统的ID想比较,如果相应,则函数执行成功返回,否则就打印错误信息,退出程序。
bypass_all();
接着bypass_all()被调用,该函数同样通过控制TAP控制器来向器件发送COT_BYPASS(0x1F)指令,使得器件进入bypass_all状态。
test_logic_reset()
接着继续调用test_logic_reset()使系统进入可靠状态。
check_rom_info(&max_erase_time, &dsize, &max_write_buffer, &block_size, &nblocks);
该函数调用了一连串的access_rom函数,access_rom函数是完成烧写的核心函数,时间已经晚了,明天继续分析
昨天分析到了check_rom_info函数,提到access_rom是整个的核心
其实这么说也不大准确,应该说access_rom是最底层操作的函数,它首先将TAP控制器状态移到ShiftDR,然后把准备好的各个引脚的电平状态设置好(没怎么搞懂高阻态是如何动作的,也许扫描链比实际引脚会多几个脚),移入扫描链中,然后把TAP控制器状态移到ShiftIR,把extest指令移入,使器件进入外部逻辑测试状态,刚才为扫描链中移入的电平就放到了引脚上。access_rom把参数addr放到器件的地址引脚上,把数据放到数据引脚上,同时把引脚原本的引脚信号移出TDO,就可以把flash返回在数据线上信号返回。
正如代码里面的那段注释:
To read data from the Flash Memory you must first fill the processor JTAG chain
with the Address, then pump the entire chain out.
however while pumping data out you can be pumping the next cycle's Address in
Therefore the JTAG chain looks like a pipeline, valid read data always coming
out one cycle late.
当前flash返回的数据要下一次扫描的时候才能返回,所以access_rom函数返回的值是上次地址读到的数据
check_rom_info的代码比较长,而且都是一些通过flash的CFI(Common Flash Interface)对flash信息简单的读取操作,这里就不再贴出来了。
check_rom_info成功返回之后,程序开始检查将要写进flash的文件的合法性,主要是大小是否合法,如果比flash还大,就返回错误信息并退出
如果成功,经过一些简单的界面交互过程之后,程序开始调用test_lock_flash来检查相应的块是否已经被lock,如果被锁定,则发送命令将其unlock,然后返回
之后,程序调用erase_flash和program,函数同样是使用acess_rom调用来在flash引脚上产生相应的时序来完成相应的操作。大家可以参考相应的flash芯片的资料。
最后,程序再把flash里面的数据读取出来进行与文件进行验证,检查烧写是否成功。
(全文完)
后记:第一次接触JTAG是大学学习数字逻辑的时候,那个时候在maxplus里面画好原理图或者用HDL写好描述,编译之后,就使用JTAG下载到alter 的芯片里面,那个芯片就按照我们的原理动起来了!!真是神奇,当时觉得那是大学里面最好玩的试验课。正是那门课,让我走进嵌入式的世界。之后开始做 DSP,是TI公司的C5402的芯片,使用的闻亭的仿真器,当时更是疑惑,为什么一个通过JTAG就能够控制住芯片的行为呢?带着一知半解,继续学习了 ARM系列的芯片,好像跟JTAG有仇一样,每个芯片(当中其实使用过一款***R的AT90S8515,使用ISP进行烧写,不过听说现在已经停产了)都有JTAG(实际上是因为JTAG确实很优秀)。于是断断续续的对JTAG有一些了解。使得我对JFlash有进行分析的原因是我们有一块44b0的板子出了问题,烧写老是出毛病,我真的就束手无策了,bootloader下不去,我天大的本事也是枉然。于是我想到了JTAG控制,既然程序是用JTAG烧写进去的,那么我用JTAG去操作、检查总应该是对的。就这样,我开始断断续续的看一下JFlash的源代码。刚开始的时候,觉得是个好复杂的问题,前面的几个函数看得还真有点吃力,不过随着对JTAG的了解增多,到后面基本上没甚么障碍了。看代码的同时,把分析的过程记录下来,希望网友们可以对Jflash有更多的了解
JTAG口及其对Flash的在线编程
通过JTAG实现对Flash在线编程。首先,介绍JTAG的定义、结构及引脚的定义,并阐述JTAG状态机的工作原理。然后,介绍JTAG口的边界扫描寄存器,给出实现JTAG在线写Flash的电路,和如何通过JTAG实现Flash的编程及程序流程图。 关键词:JTAG Flash 在线编程 随着嵌入式技术的发展,在一些高端的掌上设备中,都使用了Flash芯片,如Compaq的iPAQ、联想的天祺系列等产品。但对于研发人员来说,在开发阶段需要大量的程序调试,就意味着要对Flash进行擦除和改写的工作,因此,如何对Flash进行在线编程是问题的关键所在。本文介绍一种通过JTAG对Flash进行的在线编程方法。 1 JTAG简介 JTAG(Joint Test Action Group)是1985年制定的检测PCB和IC芯片的一个标准,1990年被修改后成为IEEE的一个标准,即IEEE1149.1-1990。通过这个标准,可对具有JTAG口芯片的硬件电路进行边界扫描和故障检测。 图1 TAP控制器的状态机框图 具有JTAG口的芯片都有如下JTAG引脚定义: TCK——测试时钟输入; TDI——测试数据输入,数据通过TDI输入JTAG口; TDO——测试数据输出,数据通过TDO从JTAG口输出; TMS——测试模式选择,TMS用来设置JTAG口处于某种特定的测试模式。 可选引脚TRST——测试复位,输入引脚,低电平有效。 含有JTAG口的芯片种类较多,如CPU、DSP、CPLD等。 JTAG内部有一个状态机,称为TAP控制器。TAP控制器的状态机通过TCK和TMS进行状态的改变,实现数据和指令的输入。图1为TAP控制器的状态机框图。
2 JTAG芯片的边界扫描寄存器 JTAG标准定义了一个串行的移位寄存器。寄存器的每一个单元分配给IC芯片的相应引脚,每一个独立的单元称为BSC(Boundary-Scan Cell)边界扫描单元。这个串联的BSC在IC内部构成JTAG回路,所有的BSR(Boundary-Scan Register)边界扫描寄存器通过JTAG测试激活,平时这些引脚保持正常的IC功能。图2为具有JTAG口的IC内部BSR单元与引脚的关系。 3 JTAG在线写Flash的硬件电路设计和与PC的连接方式 以含JTAG接口的StrongARM SA1110为例,Flash为Intel 28F128J32 16MB容量。SA1110的JTAG的TCK、TDI、TMS、TDO分别接PC并口的2、3、4、11线上,通过程序将对JTAG口的控制指令和目标代码从PC的并口写入JTAG的BSR中。在设计PCB时,必须将SA1110的数据线和地址线及控制线与Flash的地线线、数据线和控制线相连。因SA1110的数据线、地址线及控制线的引脚上都有其相应BSC,只要用JTAG指令将数据、地址及控制信号送到其BSC中,就可通过BSC对应的引脚将信号送给Flash,实现对Flash的操作。JTAG的系统板设计和连线关系如图3所示。 4 通过使用TAP状态机的指令实行对Flash的操作 通过TCK、TMS的设置,可将JTAG设置为接收指令或数据状态。JTAG常用指令如下: SAMPLE/PRELOAD——用此指令采样BSC内容或将数据写入BSC单元; EXTEST——当执行此指令时,BSC的内容通过引脚送到其连接的相应芯片的引脚,我们就是通过这种指令实现在线写Flash的; BYPASS——此指令将一个一位寄存器轩于BSC的移位回路中,即仅有一个一位寄存器处于TDI和TDO之间。 在PCB电路设计好后,即可用程序先将对JTAG的控制指令,通过TDI送入JTAG控制器的指令寄存器中。再通过TDI将要写Flash的地址、数据及控制线信号入BSR中,并将数据锁存到BSC中,用EXTEST指令通过BSC将写入Flash。
5 软件编程 在线写Flash的程序用Turbo C编写。程序使用PC的并行口,将程序通过含有JTAG的芯片写入Flash芯片。程序先对PC的并口初始化,对JTAG口复位和测试,并读Flash,判断是否加锁。如加锁,必须先解锁,方可进行操作。写Flash之前,必须对其先擦除。将JTAG芯片设置在EXTEST模式,通过PC的并口,将目标文件通过JTAG写入Flash,并在烧写完成后进行校验。程序主流程如图4所示。 通过JTAG的读芯片ID子程序如下: void id_command(void){ putp(1,0,IP); //Run-Test/Idle;使JTAG复位 putp(1,0,IP); //Run-Test/Idle putp(1,0,IP); //Run-Test/Idle putp(1,0,IP); //Run-Test/Idle putp(1,1,IP); putp(1,1,IP); //选择指令寄存器 putp(1,0,IP); //捕获指令寄存器 putp(1,0,IP); /移位指令寄存器 putp(0,0,IP); //SA1110JTAG口指令长度5位,IDCODE为01100 putp(1,0,IP); putp(1,0,IP); putp(0,0,IP); putp(0,0,IP); putp(0,1,IP); //退出指令寄存器 putp(1,1,IP); //更新指令寄存器,执行指令寄存器中的指令 putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle putp(1,0,IP); //Run-Test/Idle putp(1,1,IP); putp(1,0,IP); if(check_id(SA1110ID)) error_out("failed to read device ID for the SA-1110"); putp(1,1,IP); //退出数据寄存器 putp(1,1,IP); //更新数据寄存器 putp(1,0,IP); //Run-Test/Idle,使JTAG复位 putp(1,0,IP); //Run-Test/Idle putp(1,0,IP); //Run-Test/Idle } 6 电路设计和编程中的注意事项 ①Flash芯片的WE、CE、OE等控制线必须与SA1110的BSR相连。只有这样,才能通过BSR控制Flash的相应引脚。 ②JTAG口与PC并口的连接线要尽量短,原则上不大于15cm。 ③Flash在擦写和编程时所需的工作电流较大,在选用系统的供电芯片时,必须加以考虑。 ④为提高对Flash的编程速度,尽量使TCK不低于6MHz,可编写烧写Flash程序时实现。