【虚拟论坛置顶】(发布mkII协议引擎)[08-04-23]傻孩子的第一个大工程——自行研发的
JTAGICE mkII ISP下载开源计划“mkII搭台JTAG唱戏”——从ISP下载开始
说傻孩子喜欢跟风我也不否认,看到Armok老大进军DSP和AVR32我们怎可能不怦然心动(没有女朋友的人才会对这种事情怦然心动吧);但是,不管怎么说,前不久看到论坛里面有网友发文说,在北京搞AVR都不用本科学历,而且工资还低得出奇——这确实很打击我的自尊心。于是终于下定决心进军AVR高端阵营。无奈,我等穷人,至今拿不到mkII这样的神物,就好比玩WOW过了60级还没有骑上价值千金的座骑一样,弄了一块AP7的网络开发套件至今“狗咬刺猬无法下嘴”。
早就听说JTAG很好很强大,也一直以为其协议甚为复杂……其实都是偷懒的借口而已,今日得见,方觉相见恨晚……研究所得,不敢独享,食于众看官,觉得好的不妨捧个人场,觉得有问题的不妨给我当头棒喝——所谓众人拾柴火焰高哈^_^
开源——你好我也好^_^
>> 系统平台
目标处理器: MEGA UC3 UC3/MEGA/(Xmega?) UC3
处理器: ATMega128L ATMega8 ATMega32L ATMega32L
系统时钟: 外部16M晶体震荡器 外部7.3728M 外部20M晶体振荡器 11.0592
通信终端: RS-232 <-----> USART0 USB->RS-232 RS-232 USB<->UART
溶丝描述: 同前 同前 同前
系统电压: 5v 5v(兼容3.3v) 3.3v 3.3v
软件平台: ICCAVR
平台版本: V7.16A
工程文件: 点击此处下载工程(文件大小:730K)
mkII协议引擎: Snail mkII Protocol Engine(文件大小:13K)
工程版本:
AVR Mega v0.30beta(已发布)
AVR UC3v0.30beta(已发布)
Snail mkII for Mega(近期发布)
移植相关: HD_Support.c 和 HD_Support.h---------------如果工程进行了向其他AVR芯片的移植,直接更换或修改工程中的这两个文件
>> 相关文献
JTAGICE_mkII_Manual.pdf
AVR067:JTAGICE mkII Communication Protocol
en_ATMege128L.pdf
JTAG ICE相关资料包(文件大小:12.35M)
非官方的OCD破解资料
已经开源的JTAGICE mkII项目(使用GCC)
>> 更新日志 2008年4月23日晚上
正式公布 JTAG mkII ISP下载开源计划
厚着脸皮,趁着半夜,偷偷摸摸,抢了自己的沙发……
而且还吃着碗里的,看着锅里的……占着XX不XX……
您别急嘛……老鼠拖木屑,大头在后头……
----------------------------------------------------------
好了,不开玩笑了。弄了一晚上,可以用JTAG下程序了,脑袋都大
了。匆匆贴些代码,抑制不住自己的兴奋……但是还是不行,必须
要睡觉了……先贴这些代码算是有个汇报,占各地方,为以后详细
讲解留足余量……必须要睡觉了……原谅我ZZZZZZZZZZzzzzzzz
更新“在5V的系统上兼容3.3V的小技巧”
a、更新文章
b、更新原理简图
更新mkII协议帧解析
因为毕业实习,计划被迫推迟4天……
计划再次启动
更新mkII协议实现代码
更新AVR freak上相关的JTAG项目
我在AVR freak上搜索了很多JTAG相关的开源项目,不敢独享,特打包上传。
点击此处下载JTAG ICE相关资料包(文件大小:12.35M)
请大家关注104楼
真正的核潜艇浮出水面,他的网站中公布了完整的开源mkII、Drogen,
甚至是实现了的OCD。(虽然是英文)。
看了他的作品,我有两句话要说:
a、一坛醋晃不响,半坛粗晃啊晃——送给自己
b、老一辈虽然很厉害,不过我们年轻人就是年青人,应该抱有初生
牛犊不畏虎的精神,努力蹦一蹦。^_^
------------------------------------------------------------
获得授权,允许共享连接(Reference 107F):
点击此处下载ourdev_235715.rar(文件大小:605K)
收到百特邮寄过来的AVR32开发板UC3 JTAG下载计划正式开始
经过一夜奋斗UC3下载宣告完成,资料稍后公布
a、更新例程
b、更新文章
c、为了使用小RAM的单片机作为下载器,更新mkII数据包发送函数
更新UC3下载核心函数 更新mkII协议
a、为了解决1K SRAM情况下实现整页下载和上传得问题,特别更新了
mkII数据包的打包函数,允许在小缓冲甚至是无缓冲区的情况下
上传大数据包到PC机。
b、更新UC3下载的核心函数,同样为1K RAM系统作了优化
更新Snail_mkII_DEMO原理图
点击此处下载原理图(文件大小:20K)
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_240216.GIF
从阿莫处购得mkII下载器一个 进入协议破解阶段
a、mkII 下载计划规划完成,本贴将在完成 Mega系列的mkII下载测试以后终结。
专门针对UC3的下载在AVR32板块开贴专题讨论,并与大家一起进行OCD的破解
b、开始文章的整理
更新mkII协议核心指令解析引擎
通过该引擎,你只需要更具需要添加对应的指令即可实现功能扩展。对于未添加
的指令,引擎会自动回复Studio RSP_FAILED。对于未实现的参数这顶,引擎会自
动回复Studio RSP_ILLEGAL_PARAMETER。
JTAG专用逻辑分析仪初步制作完成。使用FPGA + AVR + JTAG_Hacker(VB编写的
上位机软件)。届时会发专贴发布。免费,开源。
关键字:FPAG VB上位机 JTAG时序 串口通讯 外中断
更新AVR Studio在mkII协议驱动时的相关备忘资料(参见7楼)
http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_259563.gif >> 在5V的系统上兼容3.3V的小技巧
开发JTAG协议,对我们很多习惯了AVR强力的端口驱动能力的人来说,也许第一次遇到需要考
虑例如Xmega、AVR32这类低电压器件的端口保护问题。这一问题主要分两个方面:
A、电平的兼容性问题
AVR mega系列是5V和3.3V都能工作的系统,但我们通常都工作在5V状态下。而AVR32和Xmega
都是低压器件,最高点压门限必须低于3.6v。这就意味着,我们的JTAG在电路上必须同时兼容
这三种器件。
简单的做法就是让整个mkII系统工作在3.3v下,对于Xmega和AVR32就能很好的解决电平的兼
容问题;对于mega系列,通过JTAG的VTref向目标系统提供3.3v电压,也可以暂时性的解决目标
IC是5V的问题。
从官方资料中,我们知道mega系列的单片机在3.3v下仅能保证最高8M(48/88/168是10M)的
工作频率,由于我们的mkII是一个简易系统,希望通过尽可能少的硬件完成原本2块M128实现的
系统功能,那我们的简易系统就很有可能要工作与极限状态下。那么较高的系统时钟应该会比较
有利(这种判断纯属个人喜好)。
如果我们试图保持下载系统工作于5V状态下,而输出JTAG信号的电平范围处于3.3v/5v可调,
硬件上我们就需要考虑电平转换。那么为了适应这种可能需求变化,软件方面应该如何处理呢?
>>修改电平的输出方式,将原本高低电平的表示方式修改为下表描述的形式
--------------------------------------------------------------------------------
希望输出的电平逻辑 DDR PORT 上拉电阻 备注
--------------------------------------------------------------------------------
1 (HIGH) IN 0 T 外部上拉
1 (HIHG) IN 1 T 内部上拉
0 (LOW) OUT 0 F
--------------------------------------------------------------------------------
这种将引脚悬浮利用上拉电阻输出高电平的方式,我称之为Release(释放)。这种方式在
I2C协议中被广泛使用。当我们的单片机工作于5V模式下,输出的高点平通过外部的上拉源来决定
这就为条线选择电平提供了可能,同时也增加了代码的适应性,一定程度上节省了可能的外部硬
件开销,降低了成本。在JTAG协议中,TAP在JTAG_AVR_RESET模式下,会自动开启输入引脚的内部
上拉(TCK、TDI、TMS),也就是说我们只需要通过VTref给目标器件供电,就能由器件自己决定
输入信号的高点平电压。对于由目标器件返回的信号TDO,我们<font color=red>不可以通过简单地
三极管电路(或者74HC08这样的IC缓冲器)来实现电平的转换,三极管那可怕的180度相位
后移会让你抓狂不已,建议关闭TDO引脚的内部上拉电阻,直接借助外部的3.3v上拉来实现——当然
这不是一种安全的方法,所以最好还是通过7400或者244或者其他专业IC缓冲器来实现吧。
B、引脚的保护。
自制的JTAG不是老虎机,因此,应该把目标器件看的如豆腐般脆弱,在所有的信号线上串联电阻
(典型值为100欧)应该是不二的选择。</font>
>>原理简图
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_226595.gif
(感谢xblAndy兄的原理图)
以下是我编写的工程中,以上思想的代码实例。
HD_Support.h —— 该模块属于硬件平台曾,因此,我们应该通过包含平台层配置文件
PF_Config.h来实现对该文件的包含。原则上,跨越模块的头文件
引用,应该统一由包含对应头文件所在的模块配置文件来实现。
# define CLR_JTAG_PIN(__PIN) DDRB |= BIT((__PIN));PORTB &= ~BIT((__PIN));NOP();
# define SET_JTAG_PIN(__PIN) DDRB |= BIT((__PIN));PORTB |= BIT((__PIN));NOP();
# define RLS_JTAG_PIN(__PIN) DDRB &= ~BIT((__PIN));PORTB &= ~BIT((__PIN));NOP();
# define PULL_UP_JTAG_PIN(__PIN) DDRB &= ~BIT((__PIN));PORTB |= BIT((__PIN));NOP();
# define READ_JTAG_PIN(__PIN) ((PINB & BIT((__PIN))) ? 1 : 0)
/*---------------------------------------------------------*
* JTAG引脚连接说明 *
* -------------------------------------------------------- *
* PB0 #SS - nsRST *
* PB1 SCK - TCK *
* PB2 MOSI - TDO *
* PB3 MISO - TDI *
* PB4 -- - TMS *
*---------------------------------------------------------*/
# define nsRST PB0
# define TCK PB1
# define TDO PB3
# define TDI PB2
# define TMS PB4
JTAG_Config.h —— JTAG模块的配置文件
//TCK
# define CLR_TCK CLR_JTAG_PIN(TCK)
# define RLS_TCK RLS_JTAG_PIN(TCK)
//TDO
# define CLR_TDO CLR_JTAG_PIN(TDO)
# define RLS_TDO RLS_JTAG_PIN(TDO)
# define PULL_UP_TDO PULL_UP_JTAG_PIN(TDO)
# define READ_TDO READ_JTAG_PIN(TDO)
//TDI
# define CLR_TDI CLR_JTAG_PIN(TDI)
# define RLS_TDI RLS_JTAG_PIN(TDI)
//TMS
# define CLR_TMS CLR_JTAG_PIN(TMS)
# define RLS_TMS RLS_JTAG_PIN(TMS) >>操作 JTAG 1149.1 的核心函数
1、JTAG TAP 状态机 及其驱动函数
^_^有待加入文字说明^_^
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_225637.gif
/***********************************************************
* 函数说明:JTAG TAP 状态机控制函数 *
* 输入: 控制序列,序列长度 *
* 输出: 无 *
* 调用函数:无 *
* -------------------------------------------------------- *
* 使用说明 *
* 1、 TMS在TCK上升边沿输出状态控制量。 *
* 2、 连续5个TCK周期在TMS上输出高电平将进入Test- *
* Logic-Reset模式。 *
* 3、 使用该函数时,请将状态机跳转以后TMS需要保*
* 持的电平也作为一个有效输入加入到序列的末尾 *
* 但描述序列长度的数值不需要相应的增加。 *
***********************************************************/
void JTAG_TAP_Control(UINT8 chCTRStream,UINT8 chLength)
{
UINT8 n = 0;
//状态机控制序列
for (n = 0;n < chLength;n++)
{
CLR_TCK
if (chCTRStream & BIT(n))
{
RLS_TMS
}
else
{
CLR_TMS
}
RLS_TCK
}
//保持电平
if (chCTRStream & BIT(chLength))
{
RLS_TMS
}
else
{
CLR_TMS
}
}
2、Shift-DR 与 Shift-IR 寄存器的数据交换
^_^有待加入文字说明^_^
/***********************************************************
* 函数说明:数据交换函数 *
* 输入: 交换数据用的输入输出缓冲,发送的二进制位长度 *
* 输出: 无 *
* 调用函数:无 *
***********************************************************/
void JTAG_Shift_Data(BYTE *pchOutBuffer,BYTE *pchInBuffer,UINT16 wLength)
{
UINT8 n = 0;
BYTE chSendData = 0;
BYTE chReceiveData = 0;
UINT16 wByteCount = (wLength & (BIT(3) - 1))
? ((wLength >> 3) + 1) : (wLength >> 3);
if (
(wLength == 0) ||
((pchOutBuffer == NULL) && (pchInBuffer == NULL))
)
{
//无效的输入
return ;
}
CLR_TMS
while(wByteCount > 1)
{
wByteCount--;
//发送一个字节
{
if (pchOutBuffer != NULL)
{
chSendData = *pchOutBuffer++;
}
else
{
chSendData = 0;
}
chReceiveData = 0;
RLS_TCK
for (n = 0;n < 8;n++)
{
CLR_TCK
//下降沿读取TDO数据
chReceiveData |= (READ_TDO << n);
//设置TDI
if (chSendData & BIT(0))
{
RLS_TDI
}
else
{
CLR_TDI
}
chSendData >>= 1;
//上升沿送出TDI数据
RLS_TCK
}
if (pchInBuffer != NULL)
{
*pchInBuffer++ = chReceiveData; //保存收到的数据
}
}
}
//发送最后一个字节
wLength = (wLength & (BIT(3) - 1))
? (wLength & (BIT(3) - 1)) : 8;
//发送最后几个二进制位
RLS_TCK
if (pchOutBuffer != NULL)
{
chSendData = *pchOutBuffer;
}
else
{
chSendData = 0;
}
chReceiveData = 0;
n = 0;
while(wLength--)
{
if (wLength == 0)
{
RLS_TMS
}
CLR_TCK
//下降沿读取TDO数据
chReceiveData |= (READ_TDO << n);
//设置TDI
if (chSendData & BIT(0))
{
RLS_TDI
}
else
{
CLR_TDI
}
chSendData >>= 1;
//上升沿送出TDI数据
RLS_TCK
n++;
}
if (pchInBuffer != NULL)
{
*pchInBuffer = chReceiveData; //保存收到的数据
}
}
3、建立JTAG的工作环境——JTAG_AVR_RESET指令
# define JTAG_TAP_TEST_LOGIC_RESET JTAG_TAP_Control(0x1F,6);
# define JTAG_TAP_SHIFT_IR JTAG_TAP_Control(0x03,4);
# define JTAG_TAP_RETURN_RUN_TEST_IDEL JTAG_TAP_Control(0x01,2);
# define JTAG_TAP_ENTER_SHIFT_DR_FROM_SHIFT_IRJTAG_TAP_Control(0x03,4);
# define JTAG_TAP_SHIFT_DR JTAG_TAP_Control(0x01,3);
^_^有待加入文字说明^_^
/***********************************************************
* 函数说明:AVR复位函数 *
* 输入: 无 *
* 输出: 无 *
* 调用函数:无 *
***********************************************************/
void JTAG_AVR_Reset(void)
{
JTAG_TAP_TEST_LOGIC_RESET
JTAG_TAP_SHIFT_IR
{
BYTE chTempData = OPCODE_AVR_RESET;
JTAG_Shift_Data(&chTempData,NULL,4);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
BYTE chTempData = 0x01;
JTAG_Shift_Data(&chTempData,NULL,1);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
}
/***********************************************************
* 函数说明:AVR离开JTAG模式函数 *
* 输入: 无 *
* 输出: 无 *
* 调用函数:无 *
***********************************************************/
void JTAG_AVR_Return(void)
{
JTAG_TAP_TEST_LOGIC_RESET
JTAG_TAP_SHIFT_IR
{
BYTE chTempData = OPCODE_AVR_RESET;
JTAG_Shift_Data(&chTempData,NULL,4);
}
JTAG_TAP_ENTER_SHIFT_DR_FROM_SHIFT_IR
{
BYTE chTempData = 0x00;
JTAG_Shift_Data(&chTempData,NULL,1);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
}
4、牛刀小试,读取设备ID看看(Read Device Identification)
^_^ 有待添加文字说明 ^_^
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_225638.gif
typedef struct
{
unsigned:1;
unsignedManufacturer:11;
unsignedPartNumber:16;
unsignedVersion:4;
}JTAG_DEVICE_ID;
/***********************************************************
* 函数说明:设备ID信息读取函数 *
* 输入: 无 *
* 输出: 读取到的ID *
* 调用函数:无 *
***********************************************************/
UINT32 JTAG_Read_Device_Identification(void)
{
UINT32 dwTempData = 0;
JTAG_AVR_Reset();
JTAG_TAP_SHIFT_IR
{
BYTE chTempData = OPCODE_IDCODE;
JTAG_Shift_Data(&chTempData,NULL,4);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
JTAG_Shift_Data((BYTE *)&dwTempData,(BYTE *)&dwTempData,32);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
return dwTempData;
}
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_225636.jpg >> 精简指令集的mkII协议
//JTAGICE mkII 的数据帧格式描述
# define AT_MF_MESSAGE_START 0x1B
# define AT_MF_SEQUENCE_NUMBER_TYPE UINT16
# define AT_MF_MESSAGE_SIZE_TYPE UINT32
# define AT_MF_TOKEN 0x0E
# define AT_MF_USE_CRC_CHECK
//STK500 的数据帧格式描述
# define AT_MF_MESSAGE_START 0x1B
# define AT_MF_SEQUENCE_NUMBER_TYPE UINT8
# define AT_MF_MESSAGE_SIZE_TYPE UINT16
# define AT_MF_TOKEN 0x0E
# define AT_MF_USE_XOR_CHECK
//(ATMEL公司下载协议数据帧的描述结构体)ATMEL Message Format Struct Description
typdef struct ATMEL_Message_Format
{
BYTE chMSGStart; //AT_MF_MESSAGE_START
AT_MF_SEQUENCE_NUMBER_TYPE SequenceNumber;
AT_MF_MESSAGE_SIZE_TYPE MessageSize;
BYTE chToken; //AT_MF_TOKEN
BYTE * pchMessageBody;
#if defined(AT_MF_USE_CRC_CHECK)
UINT16 wCRC;
#elif defined(AT_MF_USE_XOR_CHECK)
BYTE chXOR;
#else
#error Please select a Checking method: AT_MF_USE_CRC_CHECK or AT_MF_USE_XOR_CHECK.
#endif
}AT_MF;
# define SEND_MSG(__SEQ,__SIZE,__BUFF)\
{\
AT_MF_Send_MSG(MSG_MODEL_RESET,(__SEQ),(__SIZE),(__BUFF));\
while(AT_MF_Send_MSG(MSG_MODEL_SOLID,(__SEQ),(__SIZE),(__BUFF)));\
};
# define SEND_RSP_SYMPLE_MSG(__MSG) \
{\
UINT8 chTempData = (__MSG);\
SEND_MSG\
(\
SEQNumber,\
(AT_MF_MESSAGE_SIZE_TYPE)0x01,\
(void *)&chTempData\
)\
}
# define SEND_RSP_OK SEND_RSP_SYMPLE_MSG(RSP_OK)
# define SEND_RSP_FAILED SEND_RSP_SYMPLE_MSG(RSP_FAILED)
# define SEND_RSP_ILLEGAL_PARAMETER SEND_RSP_SYMPLE_MSG(RSP_ILLEGAL_PARAMETER)
# define SEND_RSP_ILLEGAL_VALUE SEND_RSP_SYMPLE_MSG(RSP_ILLEGAL_VALUE)
# define SEND_RSP_ILLEGAL_EMULATOR_MODE SEND_RSP_SYMPLE_MSG(RSP_ILLEGAL_EMULATOR_MODE)
/********************
*用户变量类型定义 *
********************/
typedef struct MCUVersion MCU_VER;
typedef struct ProductDescription PRODUCT_DESCRIPTION;
typedef BOOL (* PARAMETER_PROC_FUNC)(AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
UINT8 chAccessMode,void *pData);
typedef struct ParameterProccessItem PARAMETER_PROC_ITEM;
/********************
*模块结构体定义区 *
********************/
struct MCUVersion
{
BYTE BootLoaderVersion;
BYTE FirmwareVersionMinor;
BYTE FirmwareVersionMajor;
BYTE HardwareVersion;
};
struct ParameterProccessItem
{
UINT8 chParameterID;
unsigned R:1;
unsigned W:1;
unsigned ByteCount:3;
unsigned :3;
PARAMETER_PROC_FUNC fnParameterPROC;
};
struct ProductDescription
{
BYTE chString;
};
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_226415.gif
数据包解析状态机(暂未加入超时处理)
/********************
*用户变量类型定义 *
********************/
typedef struct AT_MF_MSGItemAT_MF_MSG_ITEM;
typedef BOOL (* AT_FM_MSG_PROC_FUNC)(AT_MF_MESSAGE_SIZE_TYPE MessageSize,
BYTE chData);
/********************
*模块结构体定义区 *
********************/
typedef struct AT_MF_MSGItem
{
BYTE chMessageID;
AT_FM_MSG_PROC_FUNC fnMSGHandler;
};
/********************
* 模块变量声明区*
********************/
#ifndef AT_MF_INSERT_MSG_MAP_ITEM
# define AT_MF_INSERT_MSG_MAP_ITEM {NULL,NULL}
# warning There is nothing in Message Map!
#endif
static AT_MF_MSG_ITEM s_AT_MF_MSGMap[] =
{
AT_MF_INSERT_MSG_MAP_ITEM
};
数据包解析函数
# define PAMA_ACTION_FLAG SET_BIT8_FORMAT(s_chActionFlag)
# define PAMA_STOP_ALL_ACTIONS s_chActionFlag = NULL;
# define PAMA_START PAMA_ACTION_FLAG.BIT0
# define PAMA_GET_SEQUENCE_NUMBER PAMA_ACTION_FLAG.BIT1
# define PAMA_GET_MESSAGE_SIZE PAMA_ACTION_FLAG.BIT2
# define PAMA_GET_TOKEN PAMA_ACTION_FLAG.BIT3
# define PAMA_GET_MESSAGE_ID PAMA_ACTION_FLAG.BIT4
# define PAMA_CALL_MSG_ROUTINE PAMA_ACTION_FLAG.BIT5
/***********************************************************
* 函数说明:ATMEL下载协议数据包解析函数 *
* 输入: 无 *
* 输出: TRUE *
* 调用函数:无 *
***********************************************************/
BOOL PROC_AT_Message_Access(void)
{
static UINT8 s_chActionFlag = NULL;
BYTE chData = 0;
#if defined(AT_MF_USE_CRC_CHECK)
static UINT16 s_wCRC = CRC_INIT;
#elif defined(AT_MF_USE_XOR_CHECK)
static UINT8 s_chXOR = 0;
#endif
static UINT8 s_chSequenceNUMCounter = 0;
static UINT8 s_chMessageSizeCounter = 0;
static AT_MF_SEQUENCE_NUMBER_TYPE s_CurrentSEQNumber = 0;
static AT_MF_MESSAGE_SIZE_TYPE s_MessageSize = 0;
static AT_FM_MSG_PROC_FUNC s_fnMessagePROC = NULL;
if (!SERIAL_IN(chData))
{
//缓冲区为空
return TRUE;
}
if (s_chActionFlag == NULL)
{
PAMA_START = TRUE;
}
if (PAMA_START)
{
//等待数据帧头部
if (chData == AT_MF_MESSAGE_START)
{
s_chSequenceNUMCounter = 0;
s_CurrentSEQNumber = 0;
#if defined(AT_MF_USE_CRC_CHECK)
s_wCRC = CRC_INIT;
CRC(s_wCRC,chData);
#elif defined(AT_MF_USE_XOR_CHECK)
s_chXOR = 0;
s_chXOR ^= chData;
#endif
PAMA_GET_SEQUENCE_NUMBER = TRUE;
PAMA_START = FALSE;
return TRUE;
}
}
if (PAMA_GET_SEQUENCE_NUMBER)
{
s_CurrentSEQNumber |= (AT_MF_SEQUENCE_NUMBER_TYPE)chData
<< (8 * s_chSequenceNUMCounter);
#if defined(AT_MF_USE_CRC_CHECK)
CRC(s_wCRC,chData);
#elif defined(AT_MF_USE_XOR_CHECK)
s_chXOR ^= chData;
#endif
s_chSequenceNUMCounter++;
if(
s_chSequenceNUMCounter
== sizeof(AT_MF_SEQUENCE_NUMBER_TYPE)
)
{
//获得了整个Sequence Number
s_chMessageSizeCounter = 0;
s_MessageSize = 0;
PAMA_GET_MESSAGE_SIZE = TRUE;
PAMA_GET_SEQUENCE_NUMBER = FALSE;
return TRUE;
}
}
if (PAMA_GET_MESSAGE_SIZE)
{
s_MessageSize |= (AT_MF_MESSAGE_SIZE_TYPE)chData
<< (8 * s_chMessageSizeCounter);
#if defined(AT_MF_USE_CRC_CHECK)
CRC(s_wCRC,chData);
#elif defined(AT_MF_USE_XOR_CHECK)
s_chXOR ^= chData;
#endif
s_chMessageSizeCounter++;
if(
s_chMessageSizeCounter
== sizeof(AT_MF_MESSAGE_SIZE_TYPE)
)
{
//获得了整个Message Size
PAMA_GET_TOKEN = TRUE;
PAMA_GET_MESSAGE_SIZE = FALSE;
return TRUE;
}
}
if (PAMA_GET_TOKEN)
{
if (chData == AT_MF_TOKEN)
{
//数据包正确
#if defined(AT_MF_USE_CRC_CHECK)
CRC(s_wCRC,chData);
#elif defined(AT_MF_USE_XOR_CHECK)
s_chXOR ^= chData;
#endif
PAMA_GET_MESSAGE_ID = TRUE;
PAMA_GET_TOKEN = FALSE;
}
else
{
//数据包不正确
//有待添加代码
PAMA_STOP_ALL_ACTIONS
}
return TRUE;
}
if (PAMA_GET_MESSAGE_ID)
{
UINT8 n = 0;
s_fnMessagePROC = NULL;
//搜索消息地图
for (n = 0;n < UBOUND(s_AT_MF_MSGMap);n++)
{
if (s_AT_MF_MSGMap.chMessageID == chData)
{
s_fnMessagePROC = s_AT_MF_MSGMap.fnMSGHandler;
break;
}
}
if (s_fnMessagePROC == NULL)
{
s_fnMessagePROC = AT_MF_DEFAULT_MESSAGE_ROUTINE;
}
PAMA_GET_MESSAGE_ID = FALSE;
PAMA_CALL_MSG_ROUTINE = TRUE;
}
if (PAMA_CALL_MSG_ROUTINE)
{
if (!s_fnMessagePROC(s_CurrentSEQNumber,s_MessageSize,chData,
#if defined(AT_MF_USE_CRC_CHECK)
s_wCRC
#elif defined(AT_MF_USE_XOR_CHECK)
s_chXOR
#endif
))
{
//完成了子状态机的调用
PAMA_STOP_ALL_ACTIONS
return TRUE;
}
}
return TRUE;
}
数据包发送函数(ver2.41)
# define AMSM_ACTION_FLAG SET_BIT8_FORMAT(s_chActionFlag)
# define AMSM_STOP_ALL_ACTIONS s_chActionFlag = NULL;
# define AMSM_START AMSM_ACTION_FLAG.BIT0
# define AMSM_SEND_HEAD AMSM_ACTION_FLAG.BIT1
# define AMSM_SEND_SEQUENCE_NUM AMSM_ACTION_FLAG.BIT2
# define AMSM_SEND_MESSAGE_SIZE AMSM_ACTION_FLAG.BIT3
# define AMSM_SEND_TOKEN AMSM_ACTION_FLAG.BIT4
# define AMSM_SEND_DATA AMSM_ACTION_FLAG.BIT5
# define AMSM_SEND_CHECK AMSM_ACTION_FLAG.BIT6
# define AMSM_IDEL AMSM_ACTION_FLAG.BIT7
/***********************************************************
* 函数说明:数据包发送函数 *
* 输入: 数据包序列号,要发送数据的大小,数据缓冲区 *
* 工作模式 *
* 输出: 状态机是否继续运行 *
* 调用函数:无 *
* -------------------------------------------------------- *
*[ 说 明 ] 该函数仅适用于大数据包的发送。 *
***********************************************************/
BOOL AT_MF_Send_MSG(UINT8 chModel,AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
AT_MF_MESSAGE_SIZE_TYPE MSGSize,
void *pMSGBody)
{
static UINT8 s_chActionFlag = NULL;
static UINT8 n = 0;
static BYTE *p = NULL;
static AT_MF_MESSAGE_SIZE_TYPE s_MessageSize = 0;
#if defined(AT_MF_USE_CRC_CHECK)
static UINT16 wCRC = 0;
#elif defined(AT_MF_USE_XOR_CHECK)
static UINT8 chXOR = 0;
#endif
if (chModel == 0xFF)
{
AMSM_STOP_ALL_ACTIONS
return FALSE;
}
if (s_chActionFlag == NULL)
{
AMSM_START = TRUE;
}
if (AMSM_START)
{
s_MessageSize = MSGSize;
if ((pMSGBody == NULL) || (MSGSize == 0))
{
//强壮性检测,不需要发送任何东西
AMSM_STOP_ALL_ACTIONS
return FALSE;
}
#if defined(AT_MF_USE_CRC_CHECK)
wCRC = 0;
#elif defined(AT_MF_USE_XOR_CHECK)
chXOR = 0;
#endif
AMSM_START = FALSE;
AMSM_SEND_HEAD = TRUE;
}
if (AMSM_SEND_HEAD)
{
if (SERIAL_OUT(AT_MF_MESSAGE_START))
{
//发送成功
n = 0;
AMSM_SEND_SEQUENCE_NUM = TRUE;
AMSM_SEND_HEAD = FALSE;
}
else
{
REFRESH_SERIAL_BUFFER
}
}
if (AMSM_SEND_SEQUENCE_NUM)
{
p = (BYTE *)&SEQNumber;
while(TRUE)
{
if (SERIAL_OUT(p))
{
//发送成功
n++;
if (n == sizeof(AT_MF_SEQUENCE_NUMBER_TYPE))
{
//发送数据完成
n = 0;
AMSM_SEND_MESSAGE_SIZE = TRUE;
AMSM_SEND_SEQUENCE_NUM = FALSE;
break;
}
}
else
{
REFRESH_SERIAL_BUFFER
break;
}
}
}
if (AMSM_SEND_MESSAGE_SIZE)
{
p = (BYTE *)&MSGSize;
while(TRUE)
{
if (SERIAL_OUT(p))
{
//发送成功
n++;
if (n == sizeof(AT_MF_MESSAGE_SIZE_TYPE))
{
//发送数据完成
AMSM_SEND_TOKEN = TRUE;
AMSM_SEND_MESSAGE_SIZE = FALSE;
break;
}
}
else
{
REFRESH_SERIAL_BUFFER
break;
}
}
}
if (AMSM_SEND_TOKEN)
{
if (SERIAL_OUT(AT_MF_TOKEN))
{
//发送成功
n = 0;
AMSM_SEND_DATA = TRUE;
AMSM_SEND_TOKEN = FALSE;
}
}
if (AMSM_SEND_DATA)
{
p = (BYTE *)pMSGBody;
while(TRUE)
{
UINT8 chTempData = 0;
if (chModel)
{
//单字节模式
chTempData = *p;
}
else
{
chTempData = p;
}
if (SERIAL_OUT(chTempData))
{
//发送成功
#if defined(AT_MF_USE_CRC_CHECK)
CRC(wCRC,chTempData) //计算CRC16
#elif defined(AT_MF_USE_XOR_CHECK)
chXOR ^= chTempData; //计算XOR
#endif
n++;
if (n == s_MessageSize)
{
//发送完成
n = 0;
AMSM_SEND_CHECK = TRUE;
AMSM_SEND_DATA = FALSE;
break;
}
else
{
if (chModel)
{
//单字节工作模式
return FALSE;
}
}
}
else
{
REFRESH_SERIAL_BUFFER
break;
}
}
}
if (AMSM_SEND_CHECK)
{
#if defined(AT_MF_USE_CRC_CHECK)
p = (BYTE *)&wCRC;
#elif defined(AT_MF_USE_XOR_CHECK)
p = (BYTE *)&chXOR;
#endif
while(TRUE)
{
if (SERIAL_OUT(p))
{
//发送成功
n++;
#if defined(AT_MF_USE_CRC_CHECK)
if (n == 2)
#elif defined(AT_MF_USE_XOR_CHECK)
if (n == 1)
#endif
{
//整个数据包发送完成
if (chModel)
{
//单字节工作模式
AMSM_SEND_CHECK = FALSE;
AMSM_IDEL = TRUE;
return FALSE;
}
else
{
AMSM_STOP_ALL_ACTIONS;
return FALSE;
}
}
}
else
{
REFRESH_SERIAL_BUFFER
break;
}
}
}
if (AMSM_IDEL)
{
return FALSE;
}
return TRUE;
}
mkII参数设定消息地图解析函数
/***********************************************************
* 函数说明:mkII参数设定消息处理函数 *
* 输入: 消息的尺寸 收到的数据 *
* 输出: 状态机是否继续运行 *
* 调用函数:无 *
***********************************************************/
BOOL mkII_Write_Emulator_Parameter(AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
AT_MF_MESSAGE_SIZE_TYPE MessageSize,BYTE chData,
UINT16 wCRC)
{
static AT_MF_MESSAGE_SIZE_TYPE s_Counter = 0;
static UINT16 s_wCRC = CRC_INIT;
static BYTE s_ParameterBuffer = {0};
static UINT8 s_chParameterID = 0;
static BYTE s_chCRCReceive = {0};
if (MessageSize == 0)
{
s_Counter = 0;
return FALSE;
}
s_Counter++;
if (s_Counter == 1)
{
s_wCRC = wCRC;
CRC(s_wCRC,chData);
TYPE_CONVERSION(s_ParameterBuffer,UINT32) = 0;
s_chParameterID = 0;
}
else if (s_Counter == 2)
{
CRC(s_wCRC,chData);
s_chParameterID = chData;
}
else if (s_Counter <=MessageSize)
{
CRC(s_wCRC,chData);
s_ParameterBuffer = chData;
}
else if (s_Counter == MessageSize + 1)
{
s_chCRCReceive = chData;
}
else if (s_Counter == MessageSize + 2)
{
s_Counter = 0;
s_chCRCReceive = chData;
if (TYPE_CONVERSION(s_chCRCReceive,UINT16) == s_wCRC)
{
//接收到了正确的数据包
UINT8 n = 0;
BOOLbFindParameter = FALSE;
for (n = 0;n < UBOUND(s_ParameterMSGMap);n++)
{
if (s_ParameterMSGMap.chParameterID == s_chParameterID)
{
bFindParameter = TRUE;
if (!s_ParameterMSGMap.W)
{
//错误的参数模式
SEND_RSP_ILLEGAL_EMULATOR_MODE
return FALSE;
}
if (!s_ParameterMSGMap.fnParameterPROC
(
SEQNumber,
PARAMTER_WRITE,
s_ParameterBuffer
)
)
{
//错误的参数模式
SEND_RSP_ILLEGAL_EMULATOR_MODE
}
return FALSE;
}
}
if (!bFindParameter)
{
//无效的参数
SEND_RSP_ILLEGAL_PARAMETER
}
}
return FALSE;
}
return TRUE;
}
让Studio认出我们的mkII
一些在mkII_Config.h中的关键宏
# define AT_MF_MESSAGE_START 0x1B
# define AT_MF_SEQUENCE_NUMBER_TYPE UINT16
# define AT_MF_MESSAGE_SIZE_TYPE UINT32
# define AT_MF_TOKEN 0x0E
# define AT_MF_USE_CRC_CHECK
# define MKII_MASTER_VERSION 0xFF,0x21,0x04,0x00
# define MKII_SLAVE_VERSION 0xFF,0x21,0x04,0x01
# define MKII_SERIAL_NUMBER 0x00,0xB0,0x00,0x00,0x41,0xB9
# define DEVICE_ID_STR "Snail JTAGICE mkII for Mega Made by Gorgon Meducer"
# define AT_MF_INSERT_MSG_MAP_ITEM \
{CMND_GET_SIGN_ON,mkII_Get_Sign_On},\
{CMND_SIGN_OFF,mkII_Sign_OFF},\
{CMND_SET_PARAMETER,mkII_Write_Emulator_Parameter}
/*
//STK500 的数据帧格式描述
# define AT_MF_MESSAGE_START 0x1B
# define AT_MF_SEQUENCE_NUMBER_TYPE UINT8
# define AT_MF_MESSAGE_SIZE_TYPE UINT16
# define AT_MF_TOKEN 0x0E
# define AT_MF_USE_XOR_CHECK
*/
# define AT_MF_DEFAULT_MESSAGE_ROUTINE mkII_Failed
# define REFRESH_SERIAL_BUFFER PROC_Serial_Transmitter();
# include "RD_UseATMELMessageFrame.h"
# include "mkII_MSGMap.h"
# include "mkII_Access.h"
/***********************************************************
* 函数说明:mkII停止DEBUG操作消息处理函数 *
* 输入: 消息的尺寸 收到的数据 *
* 输出: 状态机是否继续运行 *
* 调用函数:无 *
***********************************************************/
BOOL mkII_Sign_OFF(AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
AT_MF_MESSAGE_SIZE_TYPE MessageSize,BYTE chData,
UINT16 wCRC)
{
static AT_MF_MESSAGE_SIZE_TYPE s_Counter = 0;
if (MessageSize == 0)
{
s_Counter = 0;
return FALSE;
}
s_Counter++;
if(
s_Counter == MessageSize + 2
)
{
chData = s_Counter;
s_Counter = 0;
g_chBaudRate = 0x04;
//SEND_RSP_OK;
{
BYTE chBuffer
[
3 +
sizeof(AT_MF_SEQUENCE_NUMBER_TYPE) +
sizeof(AT_MF_MESSAGE_SIZE_TYPE) +
+ 2
] = {0};
chBuffer = AT_MF_MESSAGE_START;
TYPE_CONVERSION
(
&chBuffer,
AT_MF_SEQUENCE_NUMBER_TYPE
) = (AT_MF_SEQUENCE_NUMBER_TYPE)SEQNumber;
TYPE_CONVERSION
(
&chBuffer,
AT_MF_MESSAGE_SIZE_TYPE
) = (AT_MF_MESSAGE_SIZE_TYPE)0x01;
chBuffer
[
1 +
sizeof(AT_MF_SEQUENCE_NUMBER_TYPE) +
sizeof(AT_MF_MESSAGE_SIZE_TYPE)
] = AT_MF_TOKEN;
chBuffer
[
1 +
sizeof(AT_MF_SEQUENCE_NUMBER_TYPE) +
sizeof(AT_MF_MESSAGE_SIZE_TYPE) +
1
] = RSP_OK;
//计算交验
{
UINT16 wCRC = CRC_INIT;
UINT8 n = 0;
for (n = 0;n < sizeof(chBuffer) - 2;n++)
{
CRC(wCRC,chBuffer);
}
TYPE_CONVERSION
(
&chBuffer
[
1 +
sizeof(AT_MF_SEQUENCE_NUMBER_TYPE) +
sizeof(AT_MF_MESSAGE_SIZE_TYPE) +
2
],
UINT16
) = wCRC;
}
//这是一个使用查询模式发送数据包的函数
Put_Char(chBuffer,sizeof(chBuffer));
}
//修改通讯波特率
Set_USART_Baud_Rate(g_chBaudRate);
return FALSE;
}
return TRUE;
}
/***********************************************************
* 函数说明:mkII下载器存在状态查询消息处理函数 *
* 输入: 消息的尺寸 收到的数据 *
* 输出: 状态机是否继续运行 *
* 调用函数:无 *
***********************************************************/
BOOL mkII_Get_Sign_On(AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
AT_MF_MESSAGE_SIZE_TYPE MessageSize,BYTE chData,
UINT16 wCRC)
{
static AT_MF_MESSAGE_SIZE_TYPE s_Counter = 0;
static UINT16 s_wCRC = CRC_INIT;
static BYTE s_chCRCReceive = {0};
if (MessageSize == 0)
{
s_Counter = 0;
s_wCRC = wCRC;
return FALSE;
}
s_Counter++;
if (s_Counter == 1)
{
s_wCRC = wCRC;
CRC(s_wCRC,chData);
}
else if (s_Counter == 2)
{
s_chCRCReceive = chData;
}
else if (s_Counter == 3)
{
s_chCRCReceive = chData;
if (TYPE_CONVERSION(s_chCRCReceive,UINT16) == s_wCRC)
{
//接收到了正确的信息
BYTE Buffer;
//发送指令
Buffer = RSP_SIGN_ON;
//发送通讯协议版本
Buffer = 0x01;
//发送主从CPU版本号
TYPE_CONVERSION(&Buffer,MCU_VER) = Master;
TYPE_CONVERSION(&Buffer,MCU_VER) = Slave;
//发送序列号
{
UINT8 n = 0;
for (n = 0;n < UBOUND(SerialNumber);n++)
{
Buffer = SerialNumber;
}
}
//发送字符串
TYPE_CONVERSION
(
&Buffer+ UBOUND(SerialNumber),
PRODUCT_DESCRIPTION
) = PDescription;
SEND_MSG(SEQNumber,sizeof(Buffer),Buffer);
}
else
{
//数据包交验错误,更新统计表
//直接丢包即可
}
}
//接收可能的其他信息,提高兼容性
if(
s_Counter == MessageSize + 2
)
{
s_Counter = 0;
return FALSE;
}
return TRUE;
}
/***********************************************************
* 函数说明:无效的指令 *
* 输入: 消息的尺寸 收到的数据 *
* 输出: 状态机是否继续运行 *
* 调用函数:无 *
***********************************************************/
BOOL mkII_Failed(AT_MF_SEQUENCE_NUMBER_TYPE SEQNumber,
AT_MF_MESSAGE_SIZE_TYPE MessageSize,BYTE chData,
UINT16 wCRC)
{
static AT_MF_MESSAGE_SIZE_TYPE s_Counter = 0;
if (MessageSize == 0)
{
s_Counter = 0;
return FALSE;
}
s_Counter++;
if(
s_Counter == MessageSize + 2
)
{
SEND_RSP_FAILED
chData = s_Counter;
s_Counter = 0;
return FALSE;
}
return TRUE;
} >> Programming Via the JTAG Interface
^_^有待添加文字说明^_^
/***********************************************************
* 函数说明:编程指令序列交换函数 *
* 输入: 无 *
* 输出: 无 *
* 调用函数:JTAG_Shift_Data() JTAG_TAP_Control() *
***********************************************************/
static void JTAG_Mega_PROG_CMD_Sequence(UINT16 *pwOutBuffer,
UINT16 *pwInBuffer,UINT8 chLength)
{
UINT8 n = 0;
UINT16 wSendData = 0;
UINT16 wReceiveData = 0;
if ((pwOutBuffer == NULL) || (chLength == 0))
{
//无效的输入
return ;
}
while(chLength > 1)
{
chLength--;
//发送一个15位序列
wSendData = *pwOutBuffer++;
wReceiveData = 0;
CLR_TMS
RLS_TCK
for (n = 0;n < 15;n++)
{
if (n == 14)
{
RLS_TMS //跳出Shift-DR状态
}
CLR_TCK
//下降沿读取最后一个数据
wReceiveData |= (READ_TDO << n);
//设置TDI
if (wSendData & BIT(0))
{
RLS_TDI;
}
else
{
CLR_TDI;
}
wSendData >>= 1;
//上升沿输出TDI
RLS_TCK
}
if (pwInBuffer != NULL)
{
*pwInBuffer++ = wReceiveData;
}
//通过回到RUN_TEST_IDEL产生执行周期,非常重要!
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
}
//发送最后一个序列
wSendData = *pwOutBuffer;
wReceiveData = 0;
RLS_TCK
for (n = 0;n < 15;n++)
{
if (n == 14)
{
RLS_TMS //跳出Shift-DR状态
}
CLR_TCK
//下降沿读取最后一个数据
wReceiveData |= (READ_TDO << n);
//设置TDI
if (wSendData & BIT(0))
{
RLS_TDI;
}
else
{
CLR_TDI;
}
wSendData >>= 1;
//上升沿输出TDI
RLS_TCK
}
if (pwInBuffer != NULL)
{
*pwInBuffer = wReceiveData;
}
} >> JTAG Interface in AVR32
世界上最崩溃的事情是什么?不是TDO引脚电平无法从3.3v->5v……而是……AVR32的JTAG指令是5位的……AVR的是4位的……哈哈……我要自杀!
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_236775.gif
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_236776.gif
/***********************************************************
* 函数说明:设备ID信息读取函数 *
* 输入: 无 *
* 输出: 读取到的ID *
* 调用函数:无 *
***********************************************************/
UINT32 JTAG_Read_Device_Identification(UINT8 chInstructionType)
{
UINT32 dwTempData = 0;
chInstructionType = MIN(MAX(chInstructionType,4),8);
JTAG_AVR_Reset(chInstructionType);
JTAG_TAP_SHIFT_IR
{
BYTE chTempData = OPCODE_IDCODE;
JTAG_Shift_Data(&chTempData,NULL,chInstructionType);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
JTAG_Shift_Data((BYTE *)&dwTempData,(BYTE *)&dwTempData,32);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
return dwTempData;
}
/***********************************************************
* 函数说明:数据交换函数 *
* 输入: 交换数据用的输入输出缓冲,发送的二进制位长度 *
* 输出: 无 *
* 调用函数:无 *
***********************************************************/
static void JTAG_UC3_Shift_Data(BYTE *pchOutBuffer,BYTE *pchInBuffer,UINT16 wLength)
{
UINT8 n = 0;
BYTE chSendData = 0;
BYTE chReceiveData = 0;
UINT16 wByteCount = (wLength & (BIT(3) - 1))
? ((wLength >> 3) + 1) : (wLength >> 3);
if (
(wLength == 0) ||
((pchOutBuffer == NULL) && (pchInBuffer == NULL))
)
{
//无效的输入
return ;
}
CLR_TMS
while(wByteCount > 1)
{
wByteCount--;
//发送一个字节
{
if (pchOutBuffer != NULL)
{
chSendData = *pchOutBuffer++;
}
else
{
chSendData = 0;
}
chReceiveData = 0;
RLS_TCK
for (n = 0;n < 8;n++)
{
CLR_TCK
//下降沿读取TDO数据
chReceiveData |= (READ_TDO << n);
//设置TDI
if (chSendData & BIT(0))
{
RLS_TDI
}
else
{
CLR_TDI
}
chSendData >>= 1;
//上升沿送出TDI数据
RLS_TCK
}
if (pchInBuffer != NULL)
{
*pchInBuffer++ = chReceiveData; //保存收到的数据
}
}
}
//发送最后一个字节
wLength = (wLength & (BIT(3) - 1))
? (wLength & (BIT(3) - 1)) : 8;
//发送最后几个二进制位
RLS_TCK
if (pchOutBuffer != NULL)
{
chSendData = *pchOutBuffer;
}
else
{
chSendData = 0;
}
chReceiveData = 0;
n = 0;
while(wLength--)
{
CLR_TCK
//下降沿读取TDO数据
chReceiveData |= (READ_TDO << n);
//设置TDI
if (chSendData & BIT(0))
{
RLS_TDI
}
else
{
CLR_TDI
}
chSendData >>= 1;
//上升沿送出TDI数据
RLS_TCK
n++;
}
if (pchInBuffer != NULL)
{
*pchInBuffer = chReceiveData; //保存收到的数据
}
}
/***********************************************************
* 函数说明:UC3复位控制函数 *
* 输入: 复位控制指令 *
* 输出: Chip Protected Bit是否置位 *
* 调用函数:JTAG_Shift_Data() *
***********************************************************/
BOOL JTAG_UC3_Reset(UINT8 chResetSet)
{
BYTE chTempData;
JTAG_TAP_TEST_LOGIC_RESET
JTAG_TAP_SHIFT_IR
{
chTempData = JTAG_RESET;
JTAG_Shift_Data(&chTempData,&chTempData,JTAG_INS_TYPE_UC3);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
JTAG_Shift_Data(&chResetSet,NULL,5);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
return (chTempData & BIT(4)) ? TRUE : FALSE;
}
/***********************************************************
* 函数说明:系统挂起函数 *
* 输入: 系统是否挂起 *
* 输出: Chip Protected Bit是否置位 *
* 调用函数:JTAG_Shift_Data() JTAG_TAP_Control() *
***********************************************************/
BOOL JTAG_UC3_Halt(BOOL bEnable)
{
BYTE chTempData = 0;
JTAG_TAP_SHIFT_IR
{
chTempData = JTAG_HALT;
JTAG_Shift_Data(&chTempData,&chTempData,JTAG_INS_TYPE_UC3);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
UINT8 chData = bEnable ? 1:0;
JTAG_Shift_Data(&chData,NULL,1);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_Control(0,5);
JTAG_TAP_Control(0,5);
return (chTempData & BIT(4)) ? TRUE : FALSE;
}
/***********************************************************
* 函数说明:JTAG指令取消函数 *
* 输入: 无 *
* 输出: Chip Protected Bit是否置位 *
* 调用函数:JTAG_Shift_Data() *
***********************************************************/
BOOL JTAG_Cancel_Access(void)
{
BYTE chTempData;
do
{
JTAG_TAP_SHIFT_IR
{
chTempData = JTAG_CANCEL_ACCESS;
JTAG_Shift_Data(&chTempData,&chTempData,JTAG_INS_TYPE_UC3);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
JTAG_TAP_SHIFT_DR
{
UINT8 chTemp = 0x01;
JTAG_Shift_Data(&chTemp,NULL,1);
}
JTAG_TAP_RETURN_RUN_TEST_IDEL
}
while(chTempData & BIT(2)); //检测BUSY信号
if (chTempData & BIT(3))
{
s_bErrorFlag = TRUE;
}
else
{
s_bErrorFlag = FALSE;
}
return (chTempData & BIT(4)) ? TRUE : FALSE;
}
/***********************************************************
* 函数说明:数据寄存器数据交换函数 *
* 输入: 输出数据的缓冲,有效位数 *
* 输出: 从寄存器中移出的数据缓冲指针 *
* 调用函数:JTAG_Shift_Data() *
***********************************************************/
static BYTE *DR_Exchange_Value(const void *pBuffer,UINT8 chSize,BOOL bIfCopyResult)
{
static BYTE s_cInputBuffer = {0};
BYTE *p = NULL;
if (bIfCopyResult)
{
p = (BYTE *)pBuffer;
}
else
{
p = Small_Object_Initial(s_cInputBuffer,5,0);
}
JTAG_UC3_Shift_Data((BYTE *)pBuffer,p,chSize);
return p;
} >> Leave for unknown tittle
占位
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_240236.GIF
http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_256222.jpg
(原文件名:JTAG.jpg) >> AVR Studio mkII 协议驱动器备忘录
1、AVR Studio 在发送每一个设置指令之前,都会首先发送设置通讯波特率的指令,这个指令可以在
Advanced选项卡中设定,并且,设定后的结果会自动保存。对于mkII下载器来说,并不需要在EEPROM
中保存上一次的波特率设定。因为,Studio在每次启动时,都会默认先使用19200的波特率。
2、AVR Studio 每条指令都会以大约1秒为间隔重复发送3次。波特率设定指令发出后,必须在当前波特
率下收到下载器的应答才会进行波特率调整。
3、AVR Studio 有超时功能,对于从机无应答的情况,会自动按照超时进行处理。如果从机回复了
RSP_FAILED指令,则没有任何超时,直接弹出错误提示的窗口。
4、AVR Studio 通过依次向每一个串口发送SIGN_ON指令来自动确定下载器使用的接口,当AVR Studio
对应的mkII 窗口被关闭时,会发送一个SIGN_OFF指令。如果下载器回复RSP_OK,则窗口立即关闭,
否则,你会看到窗口仿佛失去响应了一段时间,大约3秒以后自动关闭。 沙发 不错, 谢谢,楼主出的都是精品,我顶了! 牛哦,看戏喽! 不懂是什么意思呢,不过占位.. 我也来凑热闹 顶 顶! 超级有份量的帖子。
傻孩子,不如直接搞一个: “自制 JTAG MKII 开源项目”。我单独开一个分论坛,你来主导,让更多的会员参与测试,会加快这个项目的推进的。
觉得如何? 如果觉得可行,我就创建新论坛,然后做个宣传。
这个项目如果需要我们网站的工具、零件或资金的协助,我会尽量提供。 擦亮眼睛等候。。。 占位置拉,祝贺傻孩子。
AVR32靠你拉 思维清晰,精力旺盛,注意身体. 我顶啊顶,顶啊顶!! 学习中 怎么没有硬件的图??!!! 顶一个 不错,支持一下。 to armok 阿莫
我比较喜欢热闹哈,单独弄一个板块挺冷清的,就放在AVR坛子里面不错啊。等第一个版本(JTAGICE mkII 的Mega系列下载)全部完成以后,再考虑后续的事情吧。根据目前的情况,应该可以用一个CP2102+M8完成整个下载系统(不包括Debug)。我这两天在赶进度,这个项目至少在Mega系列的下载中是完全开源的。Xmega还没有拿到芯片,暂时不敢吹牛。现在手边有AP7,弄完mega系列以后,应该会迅速进入AP7和UC3的开发部分。 傻孩子,支持你!! 多谢分享,是好东西 确实是好东西,支持!. if(明天能补考过了)
{
我就高兴的画图;
}
else if(补考又挂了)
{
我就悲痛的画图;
}
else
{
我还是找个时间画了算了;
}
傻孩子:水贴 - -b 狂顶 支持 偶像,你笑起来比周润发还帅 不错,楼主花心思了。最好方便用USB下载就更好了 CP2102是一个USB转串口的芯片,可以很方便的使用。 是的,CP2102我用来和M8535做AVRISP(STK500)很好用,从不死机,比PC卡的串口还好。唯一的问题就是和STC的下载程序有冲突,没法用,所以PC卡转的串口还在坚持上岗中...............
支持傻孩子! 严重支持,看来不玩AVR32对不起大家了。 哈哈,MK2搞定的话,对大家都是大大的好事情~~~ mkii isp已经有开源的了,方案可能不同.
要是支持debug wire(单线调试).......就帥B了 好贴,记号! 是调试用的吗? 呵呵,那是相当的帅。
曾经也想做,没找到 芯片单线仿真协议。就找到个 单线仿真的通信协议。 这个计划会首先从实现下载功能开始,至于调试,会在随后的增补版本中慢慢加入。 顶 顶一下吧,我现在用串口JTAG痛苦中,希望楼主可以做好.嘿嘿
傻孩子:谢谢鼓励。一定加油。 调试估计有点困难,我测试了一下,比如调试软件只访问一个变量时,
在RST(单线仿真脚)上会产生几百个脉冲,反正一大片,无从下手分析 以前听说AVR没有公开JTAG协议,现在公开了吗? 公开了…… 这就是为什么我把www.ouravr.com设为首页的原因,
嘿嘿,谁能帮我用英文翻译一下。怕老外看不懂, 【50楼】 Gorgon Meducer 傻孩子
公开了……
---------------
是吗?我刚才去ATMEL网站看了看,他们还是只公开了AVRSTUDIO到JTAG调试器端的协议,但好像没有公开JTAG调试器到目标MCU版之间的协议。我觉得这后一个协议才比较关键。 【52楼】 STM8
那个在各个芯片的数据手册都有介绍…… 我也搞了个类似的东西,只是做到JTAG能读目标芯片标识.烧写熔丝及擦除flash eeprom就停下来了.主要是协议问题.等一段时间我的VC学好了.我就自己定一个协议.到时就可以通过USB做一个ISP+JTAG的编程器了(目前还只能用ISP). 确实非常cool 傻孩子:加油 认真读了下代码,很厉害,学到很多东西。谢谢楼主了。有些问题请教:
1、可否解释下你整体的代码结构,看上去应该是你一个“通用结构”了。网上是否已经有了说明,如有可否给出链接,谢谢。
2、这类代码
# define JTAG_TAP_TEST_LOGIC_RESET JTAG_TAP_Control(0x1F,6);
好像你都是采用这中风格定义,或者这样
# define JTAG_TAP_TEST_LOGIC_RESET() JTAG_TAP_Control(0x1F,6)
更好些呢?因为在使用宏的代码中如果采用后者就应当写成
JTAG_TAP_TEST_LOGIC_RESET();
这更像一个函数调用,也更像C语言的语法形式。
当然,或者你有你那样做的理由,可否说明一下你为什么那样声明呢?谢谢!
3、你应该用的是软件来模拟时序,那么为什么硬件连接上要使用spi接口的那几个io引脚,难道是随意选择的吗,还是有特殊的考虑? To ifree64 :
真的很感动,你应该是仔细阅读了代码,而且有了深刻的思考。知音难寻哈。
1、第一个问题,这的确是一个通用结构,而且这个结构一直在不断的完善和更新,这次用于JTAG开发的结构是一个与以往通用结构相比,更规范的新结构版本。在我的书中关于结构有一个原则性的描述。我制作了一些工程模板,这些模板在我的BLOG中提供下载。在这个论坛中,也可以搜索到一些。由于这是只是我个人不成熟的习惯,所以在网络上还没有系统的加以说明,仅在我所指导的团队中使用(大30人左右的规模)。
2、在我的代码规范中,宏全部是大写,区别于一般的函数。你提到的宏被我定义为“动作宏”,动作宏往往是一串语句或者很多函数和语句的复合体,不能简单地等同于函数调用,所以不能那样写。而且,也许你注意到了,所有的动作宏原则上如果没有返回值,在使用时,一律不加分号——这是与函数调用严格区分的一个特征。
3、的确有考虑,为了兼容普通的ISP下载,其实,我这样设计主要是考虑一板多用,硬件上同时支持STK500和JTAG……
最后,再次谢谢您的关注。
最后,补充一件事情。昨天晚上(3月9日)突然接到辅导员的电话,要求我们软件专业进行为期4天的ERP沙盘推演互动作为毕业实习。所以这几天,这一计划不得不推迟。对不起大家了,原本到这周末就应该完成AP7的JTAG下载,不得不推迟到下周……
祝大家快乐…… 感谢傻孩子热情洋溢的回复,若真能成为你的知音,在下求之不得,欣喜万分。而现在,我还有很多要向你学习的东西呢。
“通用结构”我最开始是在21ic学到一点,是农民讲习所的帖子,让我获益匪浅呀。这次又从你的帖子学到有限状态机和通信协议在实际项目中的应用,获益良多,谢谢你们。
我是在本论坛新手入门中入门avr的,用的是gcc,还没有看过iccavr长什么样呢,呵呵;而且jtagice mkii协议还没有完全弄明白,只在头脑中有个大概,所以你的代码我还有很多部分没有完全弄明白。还有很多要学…… 还是要顶,关注中... 无限支持!
将本贴虚拟总论坛置顶,让更多人关注 :) 不知道atmel的jtag仿真协议公布没有?如果公布了就能仿真器了。
不过破解仿真协议确实要消耗很多精力,不知搂主是否破解了仿真协议? To ilikemcu 我爱单片机:
FT232BL USB转串口的芯片和STC的下载程序不会有冲突,16块钱左右一片,非常好用!
支持傻孩子! 傻孩子,聪明的孩子! 傻孩子,今天又看了一下你的代码,发现你的代码充斥着宏。通过宏C语言已经变成了一种你的方言了。我觉得宏适当使用尚可,比如条件编译;但达到你代码中的程度个人觉得有点过度。
比如:
SAFE_CODE_PERFORMANCE
(
if ((UARTTxBuffHead == UARTTxBuffTail)
&& (UARTTxBuffCounter == 0))
{
SEI();
return FALSE;
}
(*Data) = UARTTxBuff;
UARTTxBuffCounter--;
if (UARTTxBuffHead == SERIAL_TX_BUFF_SIZE)
{
UARTTxBuffHead = 0;
}
)
又是一个宏,按照你的说法是“动作宏”?
不知道你是怎么想的,总之我觉得像“文白相杂”,这样做能带来代码维护方面的好处吗?愿意听听你的意见。 转贴《effictive c++》中的第一个条款,虽然我们用的是C,但是个人认为还是应该尽可能的避免宏带来的缺陷。
条款1:尽量用const和inline而不用#define
这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。再看下面的语句:
#define ASPECT_RATIO 1.653
编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:
const double ASPECT_RATIO = 1.653;
这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,你要写两次const:
const char * const authorName = "Scott Meyers";
关于const的含义和用法,特别是和指针相关联的问题,参见条款21。
另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:
class GamePlayer {
private:
static const int NUM_TURNS = 5; // constant eclaration
int scores; // use of constant
...
};
还有一点,正如你看到的,上面的语句是NUM_TURNS的声明,而不是定义,所以你还必须在类的实现代码文件中定义类的静态成员:
const int GamePlayer::NUM_TURNS; // mandatory definition;
// goes in class impl.file
你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。
旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
在上面的语法不能使用的情况下,可以在定义时赋初值:
class EngineeringConstants { // this goes in the class
private: // header file
static const double FUDGE_FACTOR;
...
};
// this goes in the class implementation file
const double EngineeringConstants::FUDGE_FACTOR = 1.35;
大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:
class GamePlayer {
private:
enum { NUM_TURNS = 5 } // "the enum hack" — makes
// NUM_TURNS a symbolic name
// for 5
int scores;// fine
};
除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。
回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:
#define max(a,b) ((a) > (b) ? (a) : (b))
这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开车还让人痛苦。
无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即使你象这样做了,还会有象下面这样奇怪的事发生:
int a = 5, b = 0;
max(++a, b);// a 的值增加了2次
max(++a, b+10); // a 的值只增加了1次
这种情况下,max内部发生些什么取决于它比较的是什么值!
幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数(见条款33):
inline int max(int a, int b) { return a > b ? a : b; }
不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:
template<class T>
inline const T& max(const T& a, const T& b)
{ return a > b ? a : b; }
这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率(见条款22)。
顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库(见条款49),看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。 这个项目很有发展前景啊.关注 大力支持。
留个记号,关注中。。。。。。 人才啊~! 强帖,密切关注! 傻孩子不错,我们80后大有希望 谁有傻孩子BLOG的链接,很想看看。 http://www.ednchina.com/blog/RiverpigFamily/ 这帖不顶不行.
弓虽! 【53楼】 kingofkings 技术火腿(KoK)
芯片数据手册中只有边界扫描和程序下载部分的说明,片上调试的JTAG指令没有公开。这样如果要实现调试功能就只有破解这部分指令了。 傻孩子,是我错了吗?看看ISP下载和JTAG接口图。
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_230175.jpg
你的接法是(电路图如此):
PB1(SCK)---1--- TCK
PB3(MISO) ---3--- TDO
PB4(OC0)---5--- TMS
---7---
PB2(MOSI) ---9--- TDI
代码中注释如此
/*---------------------------------------------------------*
* JTAG引脚连接说明 *
* -------------------------------------------------------- *
* PB0 #SS - nsRST *
* PB1 SCK - TCK *
* PB2 MOSI - TDO *
* PB3 MISO - TDI *
* PB4 -- - TMS *
*---------------------------------------------------------*/
但我想,既然要兼容ISP下载,这样不是更好吗,ISP下载时可以直接使用avr的spi接口,不用模拟spi时序了。
MCU 2X5 ISP JTAG
(PB2)MOSI ---1---MOSI--- TCK
(PB4)OC0---3---NC --- TDO
(PB0)#SS---5---RST --- TMS
(PB1)SCK---7---SCK --- VCC
(PB3)MISO ---9---MISO--- TDI 为期4天的毕业实习终于结束了。ERP沙盘真好玩。
终于有时间来好好回答ifree64的问题了。
首先,从上面的帖子里面,你给我列举了一个不错的引脚分配方案。其实,对我来说,修改引脚,在软件上只要修改一处地方就可以实现:
对以下的宏进行修改即可
# define nsRST PB0
# define TCK PB1
# define TDO PB3
# define TDI PB2
# define TMS PB4
不过楼上也许没有注意过,我原本也有使用硬件SPI来实现JTAG的意图,而且TDI是对目标单片机来说是输入引脚,也就是说应该接我们单片机的MOSI引脚,TDO是目标单片机的输出引脚,应该接MISO,至于我们单片机上的SS引脚其实没有多大意义——我们的单片机如果工作于主机模式下,任何普通引脚都可以充当这个所谓的SS引脚的功能。
对于我说的兼容STK500,仅仅是指软件上的兼容,电路上可能会针对不同的引脚接口做一些走线上的小修改。
关于宏的问题,我很高兴你给我中肯的指出了这么多。其实,你所说的问题我都是仔细思考过的,你给我提供的文献,我也一直引以为经典。不过呢,我还是想辩解一二:
1、C++ 虽然提供了 inline和const不过这些语句和宏还是有相当的差别的。首先,需要注意变量和真正意义上常量的区别在于是否占用了存储空间,const修饰的仍然是变量,因为它占用了存储空间,而且可以通过指针和强制类型转换绕过,从而进行修改(这就是所谓的c语言的缺陷之一);const修饰的对象应该被称之为“不应该被修改的变量”而不是“常量”。与之相对应宏所描述的常量就是真正的常量,在编译时刻由编译器将预编译时产生的实际内容像填写表格一般放到目标代码的合适位置;const修饰的常量,会占用存储空间,在代码未进行优化的情况下,所有的编译器几乎都会采用访问变量的方法从制定的存储空间读取相应的数值。关于inline,应该说是很好的模拟了“动作宏”,而且加入了语法检测的功能。这是C++中一个成功的地方,值得肯定。不过,从使用C的角度来说,也有它自己的另外解释(第二条来说明)。
2、如果你再仔细看一下,我并不是胡乱的用宏,也不是故意文白相杂,我是严格遵循一定原则的。
A、我只会在容易发生改变,或者需要外部提供接口和信息的地方使用宏;
例如:
//TDI
# define CLR_TDI CLR_JTAG_PIN(TDI)
# define RLS_TDI RLS_JTAG_PIN(TDI)
//TMS
# define CLR_TMS CLR_JTAG_PIN(TMS)
# define RLS_TMS RLS_JTAG_PIN(TMS)
B、对于结构复杂的表达式,一般需要使用宏,例如MIN() 和 MAX() 宏
C、对于那些常用的函数功能,写成函数代码又效率不高的,一般需要使用宏,例如
ABS()宏:# define ABS(__VALUE) ((__VALUE) < 0 ? -(__VALUE) : (__VALUE))
这样的宏可以避免函数调用时的系统开销,而且天然的兼容不同的有符号整形和浮点型;
D、对于那些结构相同而又容易混淆的代码片断,应该使用宏给这些相近的代码赋予一定的解释,例如:
# define JTAG_TAP_TEST_LOGIC_RESET JTAG_TAP_Control(0x1F,6);
# define JTAG_TAP_SHIFT_IR JTAG_TAP_Control(0x03,4);
# define JTAG_TAP_RETURN_RUN_TEST_IDEL JTAG_TAP_Control(0x01,2);
# define JTAG_TAP_ENTER_SHIFT_DR_FROM_SHIFT_IRJTAG_TAP_Control(0x03,4);
# define JTAG_TAP_SHIFT_DR JTAG_TAP_Control(0x01,3);
E、为了提高代码的可读性,屏蔽复杂而无必要的代码细节,应该使用宏。例如:
_PD1 = HIGH; //有空可以试着把这个宏进行展开
关于这一点,MFC比我夸张多了……
F、为了工程结构上的需要,我这里就不说著名的#ifndef的结构来防止.h重复包含,以及利用EXTERN宏来
实现全局变量的自动声明(引用);但说我常用的方法,就足以举例:
为了实现底层硬件初始化部分与工程进行有效的隔离,对于资源的中断处理函数,我采用宏的方法将外部
代码插入到模块文件中:
/***********************************************************
* 函数说明:串口发送完成中断处理函数 *
* 输入: 无 *
* 输出: 无 *
* 调用函数:INSERT_USART0_TX_ISR_CODE *
***********************************************************/
void USART0_TX_ISR(void)
{
INSERT_USART0_TX_ISR_CODE
}
G、决不允许在参数宏中使用复杂表达式,例如,不允许在参数宏中使用 自加“++”或者自减“--” 操作
一口气说了这么多,希望你能体会到:
宏是一个古老的东西,如果说从1946年计算机诞生到现在,可以被看成地球的演化历史,那么宏就是计算机界的活化石(和熊猫一样)。从最早的汇编语言,就是利用宏将常见的二进制指令替换为容易懂得短语,从而在一定程度上避免了将这些二进制指令写错的可能,再到后来宏演化为:变量、保留字等等。宏的本质就是助记符,首先利用约定的文本实现占位,接着根据需要将文本进行替换。有人说,宏是危险的,是C语言的一大缺陷,这种说法虽然过激,但是不无道理——对于没有正确利用宏,或者所没有按照一定的原则坚持正确使用宏(什么叫做正确?一以贯之的坚持按照某一原则使用宏,就是正确),那么宏会带来代码维护上的尴尬,也许这才能称之为“文白相杂”吧。但是,我决不认为,我是文白相杂。我坚持了原则,并且这一原则是本着提高代码可读性为宗旨的,那么,我自认为这样的宏就是安全的。 谢谢傻孩子这么精彩的回复,从你的回复中学到很多。
关于宏,我从来没有想到它甚至和汇编语言的助记符能联系起来,那么有深意,还是你思考得深入一些。我同意你的观点,必须要一以贯之的按照一个原则来使用宏,这样才能避免宏给我们带来的危险。你一一罗列出了你使用宏的理由,和在什么情况下使用宏的原则,所以我觉得你用“宏”改造了C语言,使它成为了一种你的方言。虽然再讨论是否使用宏的问题,有违背本帖主旨,而且这纯粹是个人编程风格 的问题,是无所谓对错的;但我还是想说说我反对宏的理由,在你列出如此多的理由后,仍然不能说服我向你那样去使用宏的理由。
宏是预处理器处理的,而我赞同“尽量用编译器而不用预处理”。这是最根本的理由,所以我只在不得不用宏的时候用,否则用其他方法代替。因为我不能保证我自己不犯错误,比如,你说的
B、对于结构复杂的表达式,一般需要使用宏,例如MIN() 和 MAX() 宏
C、对于那些常用的函数功能,写成函数代码又效率不高的,一般需要使用宏,例如
ABS()宏:# define ABS(__VALUE) ((__VALUE) < 0 ? -(__VALUE) : (__VALUE))
这样的宏可以避免函数调用时的系统开销,而且天然的兼容不同的有符号整形和浮点型;
虽然使用宏带来了简洁,但是你也看到了,为了保证不出错误,我得加上一层又一层的括号,如果一时疏忽少加了一个,编译不会告诉我,它会告诉我一个莫名其妙的错误。程序员经常熬夜,难保那天我不会因为疲倦而犯下这样的错误,但是由于编译器不能准确告诉我错误位置,为除错我不得不再多熬几个夜,这是不能忍受的。
当然,我也知道很多地方,除了宏,我们没有其他好的办法,比如你所说的:
_PD1 = HIGH; 等等。
结合你所说的,我总结一下我对宏的态度:
1、在可能的情况下,尽量避免使用宏,而使用编译器的特性取得它;
2、在不得不用宏的时候,认识清楚宏会带来的缺陷,以一种基本原则使用之,避免麻烦。
回到JTAG的制作上来。ISP下载接口和JTAG下载接口有很多致命的冲突,比如
isp中4号脚是GND,而JTAG中是VTref,
JTAG中2号脚是GND,isp确实VTag
这样一来,如果JTAG接口插入到目标板ISP中,会造成目标板isp插座2号脚到GND的短路;和JTAG的Vtref到GND的短路。
我想到如下的方法:
方案1、JTAGICE和目标板都各自使用自己的电源,只在10号脚上共地。2、4、8都悬空;或者
方案2、作为JTAG时,通过上拉IO口检查4号脚状态,如果为高电平,控制一电子开关接通4号脚电压,向目标板供电。
作为ISP时,JTAGICE不需要目标板供电,所以2号脚可以悬空,或者如上方法向目标板供电。
方案3、使用跳线,但个人不喜欢这个方案,因为这把系统的安全完全交给了用户自己。
不知道你有什么好的方法?
另外你在1楼中说到:
在JTAG协议中,TAP在JTAG_AVR_RESET模式下,会自动开启输入引脚的内部
上拉(TCK、TDI、TMS),也就是说我们只需要通过VTref给目标器件供电,就能由器件自己决定
输入信号的高点平电压。
我理解你的电平兼容方式为把IO口设置为开漏输出,用目标板的上拉来决定高电平的大小。如果我理解没错,那么你文中所说的由VTref来给目标器件供电就有问题了。如果在JTAGICE中VTref接的VCC,你的VCC是5V,怎么能用这个5V给目标板供电呢?除非JTAGICE中已经把5V稳压至3.3V,才能把这个3.3V接VTref把,否则5V上拉已经违背了你的初衷了。 我不会用同一个10心接口去同时兼容JTAG和ISP,我会使用不同的接口,或者采用条线的方法改变部分引脚顺序。至于JTAGICE给器件供电的问题,我的意思就是已经把5V稳压到了3.3V,因为稳压容易,而信号转换比较麻烦。 呵呵,我钻牛角尖了。用两个10心接口,你的方案就比我的好得多了。 请再仔细想一下,JTAG与ISP是可以自动由程序控制的.用一个接口也是可以的 铺张报纸,坐地上看LZ 我认为用多少宏不是问题,关键是宏的嵌套太深且交错才可怕。。。也许是"ifree64"所说的"文白相杂"吧. 不错,深受启发 留名 太有才了,祖国的未来就靠你了 顶一下,顺便做个记号! 高人啊,不顶不行 看到这个,想问楼主一个问题,这个状态机的图使用什么工具画的,rose吗? 这个状态机来自官方截图。不过这样的图形用word就能轻松画出来。visio也是不错的选择。 傻孩子,我也问你个关于画图的问题,凑个热闹。请问你书中的那些图是用什么软件画的?也是用word?岂不是很累?还有datasheet中的那些时序图啊,结构框图啊都是用什么画的?谢谢了! 有没有人知道ft2232,这个芯片带usb接口,而且内部集成Multi-Protocol Synchronous Serial Engine (MPSSE)接口,
用官方提供的MPSSE JTAG DLL ,再有vc的编程基础,我相信可以做出个很不错的jtag。
国外比较流行的开源项目Open-Ocd-jtag就是用了这款芯片。
官方网站http://www.ftdichip.com/
http://www.ftdichip.com/Products/FT2232C.htm to【91楼】 ifree64
我书中所有的图几乎都是word画的,也不是很累哈。
to【92楼】 toplow
这些内容我们都搜索过,在avrfreak上的。但是,他们都没有自己编写源代码,都使用的是官方的firmware。所以我这个项目应该不冲突的。不过我会把你说的东西打包上传上来的。注意关注1楼。 那些图都是word画的?佩服ing 谢谢傻孩子共享出来的资料。我大概的看了看,发现都是用avr bootloader和avr studio来更新fireware的方法来制作JTAG ice的。好像都没有JTAG OCD调试部分的源代码。我看了你所列出的资料和ATMEGA16的数据手册,发现都没有JTAG 调试部分的资料。请问你是否有这部分的资料?如果有能否共享出来,谢谢! 高手真多啊!仰慕! 请问下楼主,软件平台只能用ICCAVR吗?AVR Studio支持吗?我昨天刚好拿到了阿莫的一块128的转换板,今天DIY了一个,后来要用的时候才发现在软件平台是ICCAVR,我现在手上的最小系统板还没有JTAG接口,试不了。
还是说那些程序是用ICCAVR编译的 To 【97楼】 2006cc
我所有的程序都是基于ICC平台的。不过这次的项目有意回避了使用ICC特性的一些代码,所以可以很方便的移植到别的平台上,需要改动的文件只有HD_Support.c和HD_Support.h。
To 【95楼】 ifree64
果然一针见血哈。OCD协议我正在努力通过逻辑分析仪进行破解。 To:
现在我做好了一个Mega128L,将那个SNAIL_JTAG.hex程序写进里面去了。然后也接上串口,打开AVR Studio,按联接结果不成功。我系统板是3.3V的,而那个“JTAGICE mkII ISP”板是5V的。不知道是哪里出了问题? 呵呵,果然是破解。不知道下面的连接对你有没有帮助?但我想你应该google过了
http://download.savannah.gnu.org/releases/freeice/AVR-OCD-Documentation.html
AVR JTAG OCD (Private) Commands
Document Date 05 April 2003
JTAG Instruction 0x08 - Force Break
JTAG Instruction 0x09 - Run
JTAG Instruction 0x0A - Execute AVR Instruction (2 Words!)
use 0x0A, SDR 0xFFFF0000 to read PC (actually returns PC+2 or PC+4)
JTAG Instruction 0x0B - Access OCD Registers
there are total 16 Addressable Registers
after IR next DRSHIFT is RW Flag (1=Write) + 4 Bits Address
those Data in Instruction is 21 (5 + 16) bits
note for read operation OCD Address need to be pre latched!
Register 0 PSB0
Register 1 PSB1
Register 2 PDMSB
Register 3 PDSB
Register 8 Break Control Register (BCR)
Bit rw Description
D15 rw 1=Enable Timers to Run during Break
D14 rw 1=PC is read as +4 not +2 after break ?
D13 rw 1=Break on change Flow ?!
D12 rw 1=Enable PSB0
D11 rw 1=Enable PSB1
D10 rw 1=Enable PDMSB as single break
D9 rw 1=Enable Mask in Break Comparison
D8 rw 1=
D7 rw 1=*
D6 rw 1=
D5 rw 1=
D4 rw 1=*
D3 rw 1=*
D2 rw 1=
D1-0 r (read as 0)
* note when D7, D4, D3 are all set then PDSB is enabled s Program Break
Register 9 - Break Status Register (BSR)
Bit rw Description
D15-D8 r
D7 r 1=Break on change flow
D6 r 1=Break on PSB0 (Reg0)
D5 r 1=Break on PSB1 (Reg1)
D4 r 1=Break on PDMSB (Reg2 as single break)
D3 r 1=Break on PDSB (Reg3)
D2 r 1=Break on ? (has been seen)
D1 r 1=Break forced by OCD (Instr 8)
D0 r 1=Break by AVR Break Instruction (0x9598)
Register C - OCDR Readback
Bit rw Description
D15-8 rw OCDR 7..0
D7-0 r unused (read as 0)
Register D - Control and Status Register
Bit rw Description
D15 rw 1=Enable OCDR
D14 rw 1=?
D13-D5 r
D4 r 1=OCDR written by AVR and not read by OCD
D3 r 1=Reset not active
D2 r 1=Reset not active
D1-0 r to 【100楼】 ifree64
谢谢,帮助很大。不过我目前工作的重点不是OCD。二是UC3的JTAG下载。等完成了所有的JTAG下载以后,我才会回来解决OCD的问题。
to 【99楼】 2006cc
我在论坛上提供的工程暂时还不能连接到Studio。这个工程的主要目的是为大家演示如何利用JTAG编写ISP程序。在工程中提供了详细的JTAG函数和ISP下载函数。并没有提供mkII协议部分。具体的mkII协议部分,我还没有公布——因为还有很多需要测试和实现的工作。 哦!谢谢! 大力支持免费开源
让那些收钱的人、不开源的人去见鬼吧