|
2楼
楼主 |
发表于 2008-4-27 17:47:20
|
只看该作者
>>JTAG Hacker 开源项目
[原理解析]
JTAG Hacker顾名思义,就是JTAG的Hacker啦。JTAG协议,本质上就是SPI的兼容协议加上TAP状态机。
其中我们可以把TCK等同于SPI的SCK,把TDI和TDO分别等同于MOSI和MISO;剩下一个TMS并不是SS,而是用
作TAP状态机的控制。从JTAG协议中,我们知道,TMS在TCK的上升沿被读入TAP,用于驱动状态机。而TDI
信号,同样也是在TCK的上升沿被读取到目标设备中。
JTAG Hacker本质上就是一个逻辑分析仪。根据TCK的边延触发(上升沿和下降沿都触发),依次读取
TCK、TDI、TDO、TMS引脚上的电平。当JTAG工作频率在100K以下的时候,我们甚至可以直接使用AVR单片
机来做信号采样,并把采样的结果通过串口发送出去。在PC机端,我们可以利用VB、VC等开发工具驱动串
口,读取结果,并将信号绘制在屏幕上。
[需求分析及方案选定]
根据实际测试,AT JTAGICE mkII的JTAG工作频率在AVR32 Studio下是不可调的,最高频率达到8M。
在这种情况下,采用AVR直接进行信号采样,貌似至少Mega系列是不大可能的,至于Xmega倒是尚未测试,
AVR32肯定不在话下……用FPGA因该是必然的选择。
用FPAG完成什么功能呢?简单情况下,让FPGA根据TCK信号的边沿读取JTAG时序,并将时序缓冲下来
以一个额定的缓慢的速度(比如10KHz)在另外一个端口中输出出来,我们可以直接使用单片机采样获得
这些信号,处理过后发送给上位机。这种方案,对FPGA编程要求很低,几乎人人都可以尝试。
对于很多FPGA搞手来说,直接根据TCK信号进行采样,完成编码以后利用串口发送给PC机可谓小菜一
碟。对于高手,当然更推荐这种方法啦。搞不好,我们还可以弄出一个JTAG专用逻辑分析仪呢。考虑到傻
孩子手下创新实践班学生的实践经验,采用FPAG+AVR+PC的方案。JTAG Hacker的后续版本,将采用FPGA+
PC的方法直接形成成品。
[FPGA部分]
JTAG Hacker FPGA采样端程序(文件大小:3.67M)
module LogicAnalyze (
g_CLK,
EN,
FeedBack,
TCK_IN,
TDO_IN,
TDI_IN,
TMS_IN,
TCK_OUT,
TDO_OUT,
TDI_OUT,
TMS_OUT,
TCK_IN_TEMP,
State,
TempCLK
);
input g_CLK,
EN,
TCK_IN,
TDO_IN,
TDI_IN,
TMS_IN,
TCK_IN_TEMP;
output TCK_OUT,
TDO_OUT,
TDI_OUT,
FeedBack,
State,
TempCLK,
TMS_OUT;
parameter BufferSize = 512;
reg Init = 0;
reg Flag = 1;
reg ENFlag = 1;
reg TempTCK;
reg TCKBuffer[0:BufferSize - 1];
reg TDOBuffer[0:BufferSize - 1];
reg TDIBuffer[0:BufferSize - 1];
reg TMSBuffer[0:BufferSize - 1];
reg State = 0;
reg TCK_OUT = 0;
reg TDO_OUT = 0;
reg TDI_OUT = 0;
reg TMS_OUT = 0;
reg FeedBack = 1;
reg TempCLK = 0;
integer CLKCounter = 0;
integer BufferHead = 0;
integer BufferTail = 0;
integer BufferCounter = 0;
integer BufferCounterTemp = 0;
always @(posedge g_CLK)
begin
if(BufferCounter == 1'b0)
begin
FeedBack <= 1;
BufferHead = 1'b0;
BufferTail = 1'b0;
end
else
begin
FeedBack <= 0;
end
if((TCK_IN == 1'b1) && (Flag == 1'b0))
begin
Flag <= 1;
if(BufferCounter < BufferSize)
begin
TCKBuffer[BufferTail] <= TCK_IN_TEMP;
TDOBuffer[BufferTail] <= TDO_IN;
TDIBuffer[BufferTail] <= TDI_IN;
TMSBuffer[BufferTail] <= TMS_IN;
BufferCounter <= BufferCounter + 1'b1;
BufferTail = BufferTail + 1'b1;
if(BufferTail == BufferSize)
begin
BufferTail = 1'b0;
end
end
end
else if((TCK_IN == 1'b0) && (Flag == 1'b1))
begin
Flag <= 1'b0;
if(BufferCounter < BufferSize)
begin
TCKBuffer[BufferTail] <= TCK_IN_TEMP;
TDOBuffer[BufferTail] <= TDO_IN;
TDIBuffer[BufferTail] <= TDI_IN;
TMSBuffer[BufferTail] <= TMS_IN;
BufferCounter <= BufferCounter + 1'b1;
BufferTail = BufferTail + 1'b1;
if(BufferTail == BufferSize)
begin
BufferTail = 1'b0;
end
end
end
if((EN == 0) && (ENFlag == 1))
begin
ENFlag = 0;
State <= ~State;
if(BufferCounter != 0)
begin
TCK_OUT <= TCKBuffer[BufferHead];
TDO_OUT <= TDOBuffer[BufferHead];
TDI_OUT <= TDIBuffer[BufferHead];
TMS_OUT <= TMSBuffer[BufferHead];
BufferCounter <= BufferCounter - 1;
BufferHead = BufferHead + 1'b1;
if(BufferHead == BufferSize)
begin
BufferHead = 1'b0;
end
end
end
else if((EN == 1) && (ENFlag == 0))
begin
ENFlag = 1;
end
end
/*************************************************************************/
/*always @(negedge EN)
begin
FeedBack = ~FeedBack;
if(BufferCounter > 1'b0)
begin
//FeedBack <= 1'b0;
TCK_OUT <= TCKBuffer[BufferHead];
TDO_OUT <= TDOBuffer[BufferHead];
TDI_OUT <= TDIBuffer[BufferHead];
TMS_OUT <= TMSBuffer[BufferHead];
BufferCounterTemp = BufferCounter - 1;
BufferCounter = BufferCounterTemp;
if(BufferCounter == 1'b0)
begin
// FeedBack <= 1'b1;
end
BufferHead <= BufferHead + 1'b1;
State <= ~State;
if(BufferHead == BufferSize)
begin
BufferHead <= 1'b0;
end
end
end
*/
always @(posedge g_CLK)
begin
CLKCounter = CLKCounter + 1;
if(CLKCounter >= 1000)
begin
CLKCounter<= 0;
TempCLK = ~TempCLK;
end
end
endmodule
[AVR 部分]
更新一处BUG,该BUG有一定概率导致与FPGA通讯时数据丢失
点击此处下载 JTAG Hacker AVR端采样程序 (文件大小:96K)
[PC上位机]
符合公共通信协议的下位机都可以使用该软件进行JTAG时许分析。
点击此处下载 JTAG Hacker 上位机VB工程文件(文件大小:37K)
[注]图中所示的时序是测试用的时序,没有任何意义。
[公共通信协议]
下位机协议:
a、数据包格式
0xAA + DATA + ~DATA 即:帧头为0xAA,数据为DATA,用一个取反了的DATA作为
交验
b、发送方法
下位机发送数据包给上位机,并等待上位机的回应。如果上位机回复0xAC,则表示数据接收
正确;如果上位机回复0xED,则表示数据接收错误,下位机应该重发数据包。对于上位机其
它回复数据,一律无视。如果在一定时间长度内(典型为100ms)没有收到数据包,则直接
发送下一数据包。
c、典型发送代码
BOOL PROC_Read_JTAG(void)
{
static BYTE s_chActionFlag = NULL;
static BYTE s_chTempData = NULL;
static BYTE s_chDataBuffer[3] = {0xAA,0,0};
static UINT8 s_chCounter = 0;
if (s_chActionFlag == NULL)
{
s_chActionFlag = 0x01;
}
if (s_chActionFlag == 0x01)
{
//发送下降沿
_PB3 = HIGH;
NOP();
_PB3 = LOW;
s_chActionFlag = 0x02;
}
if (s_chActionFlag == 0x02)
{
if (PIN_PD2 == LOW)
{
//读取到了数据
s_chTempData = ((PINE & BIT(PE6)) ? 1:0)|
((PINC & BIT(PC7)) ? 2:0)|
((PINA & BIT(PA4)) ? 4:0)|
((PINA & BIT(PA5)) ? 8:0);
s_chDataBuffer[0] = 0xAA;
s_chDataBuffer[1] = s_chTempData;
s_chDataBuffer[2] = ~s_chTempData;
s_chCounter = 0;
s_chActionFlag = 0x03;
}
else
{
s_chActionFlag = NULL;
}
}
if (s_chActionFlag == 0x03)
{
//发送数据
if (SERIAL_OUT(s_chDataBuffer[s_chCounter]))
{
s_chCounter++;
if (s_chCounter == sizeof(s_chDataBuffer))
{
//发送完成
s_wCommunicationTimeCounter = 100;
s_chActionFlag = 0x04;
}
}
}
if (s_chActionFlag == 0x04)
{
UINT8 chData = 0;
if (SERIAL_IN(chData))
{
if (chData == 0xAC)
{
//数据被正确接收
s_chActionFlag = NULL;
}
else if (chData == 0xED)
{
//数据接收错误,重发
s_chCounter = 0;
s_chActionFlag = 0x03;
}
}
else if (s_wCommunicationTimeCounter == 0)
{
//发生了超时,默认继续发送
s_chActionFlag = NULL;
}
}
return TRUE;
}
上位机协议:
a、等待帧头部0xAA,其余数据一律丢弃。
b、依次接收DataA和DataB。如果DataA与DataB互为反码,则发送0xAC,否则发送0xED。
c、典型代码
Function FrameCheckStatueMachineEngine(ByVal chInData As Byte, ByRef chOutData As Byte) As Boolean
On Error Resume Next
Static s_nActionFlag As Integer
Static s_chDataA As Byte
FrameCheckStatueMachineEngine = False
If (s_bIfStartDelay = True And s_nCommunicationTimeCounter = 0) Then
'上一次发生了超时
s_nActionFlag = 0
StatusBar.Panels(2).Text = "Time out occur!"
End If
If (s_nActionFlag = 0) Then
s_nActionFlag = 1
End If
If (s_nActionFlag = 1) Then
'等待头部
If (chInData = &HAA) Then
'接收到了头部
s_nActionFlag = 2
s_nCommunicationTimeCounter = 2
s_bIfStartDelay = True
End If
Exit Function
End If
If (s_nActionFlag = 2) Then
'等待第一个数据
s_chDataA = chInData
s_nActionFlag = 3
Exit Function
End If
If (s_nActionFlag = 3) Then
'等待第二个数据
ReDim chData(1) As Byte
If s_chDataA = Not chInData Then
'数据校验正确
chData(0) = &HAC
chOutData = s_chDataA
FrameCheckStatueMachineEngine = True
Else
'数据校验错误
chData(0) = &HED
End If
'返回
COM.Output = chData
s_bIfStartDelay = False
End If
End Function |
|