ALTERA CPLD离线烧写方案设计(MCU模拟JTAG)

在含有CPLD芯片的电子产品中,由于代码中的BUG需要升级固件,如果以前的固件内没有离线烧写系统,那么必须要通过专门的烧写工具把固件下载到CPLD中去(如USB Blaster),但这样非常繁琐,而且不方便售后服务,所以代码内集成离线烧写系统的重要性可见一斑。
废话不多说,直接进入正题!!!

方案一:ALTERA 官方Jam STAPL Byte-Code Player Version 2.2

点击官方源码跳转到官方下载页面
该方案可移植到DOS、嵌入式(包括STM32等MCU)、windows等平台,采用.jbc二进制文件(可以由quartus软件生成)作为程序文件进行编程。
移植到MCU(STM32为例子)额外注意事项如下:
1、JBC文件中的数据到提出出来存放到一个数组中(由jbc2data.c得到)
2、移植参考STM32的CPLD离线烧写系统设计.pdf、源码中的readme.txt、AN 122 Using Jam STAPL for ISP via an Embedded Processor.pdf文档
3、根据平台屏蔽或者删除掉不相关的函数、头文件
4、Jam STAPL Byte-Code Playe源码中的标准请参考jesd71_stapl.pdf
5、源码本身占用大概20K的空间,另外还要占用大概16K以上的RAM空间(因为代码中申请了非常多的堆空间)
6、.jbc文件可由quartus II ->代码下载页面 -> file -> create Jam、Svf、Jbc… -> Jam STAPL Byte-Code 2.0(.jbc)生成 (方案二的.svf文件也在这里生成,一般选择1MHz的TCK频率)

在这里插入图片描述

移植后成功升级CPLD固件的输出信息:
在这里插入图片描述

方案二:由SVF文件获得编程细节,模拟JTAG进行编程

重要参考文章:
1、MCU模拟JTAG接口对LATTICE CPLD FPGA 进行在线编程加载
NOTE:
1)、该文章内JTAGState结构体中的Pattern为TMS对应不同状态的值,如IDLE->SHIFTIR,TMS从1->1->0->0变化(计为0xC0),共4个TCK。
2)、Lattice与Altera的SVF文件有很大区别,所以只需要看懂Excute_SIR、SDR、Set_JTAG_State_Machine()等几个函数即可

2、ARM JTAG 调试原理.pdf(仔细读懂里面的状态机转换)

SVF文件部分细节如下(生成方法同生成.jbc文件类似,注意TCK频率不宜过高,1MHz即可):

!
!
!
TRST ABSENT;
ENDDR IDLE;
ENDIR IRPAUSE;
STATE IDLE;
SIR 10 TDI (2CC);
RUNTEST IDLE 1003 TCK ENDSTATE IDLE;
!
!
!
!CHECKING SILICON ID
!
!
!
SIR 10 TDI (203);
RUNTEST 8 TCK;
SDR 13 TDI (0089);
SIR 10 TDI (205);
RUNTEST 8 TCK;
SDR 16 TDI (FFFF) TDO (8232) MASK (FFFF);
SDR 16 TDI (FFFF) TDO (2AA2);
SDR 16 TDI (FFFF) TDO (4A82);
SDR 16 TDI (FFFF) TDO (8C0C);
SDR 16 TDI (FFFF) TDO (0080);

方案思路:因为.svf文件描述的是JTAG的编程细节,只要我们从.svf文件中提取出相应数据,包括指令数据、输入输出数据等,然后按照对应指令执行即可。
例子:

SIR 10 TDI (203);

该语句表示发送10位指令数据0x203;通过算法处理该语句,提取出该语句的有效信息为"IR"指令、“10"位数据、数据为“0x203”,MCU模拟JTAG编程时,先匹配命令"IR",再发送相应位数的指令数据即可,其他命令同理可得(提取算法需要自己写,可用Qt的正则表达式提取)。

	//命令可以用如下数据对应
    typedef enum{
        RESET_CMD    = 0x00,
        IDLE_CMD     = 0x01,
        RUN_TCK      = 0x02,
        RUN_IDLE_TCK = 0x03,
        SIR_CMD      = 0x04,
        SDR_DIR      = 0x05,
        SDR_TDO      = 0x06,
        SDR_TDO_MASK = 0x07,
        INVALID_CMD  = 0xFF
    }JTAG_CMD;

重要提示:.jbc的编程波形几乎与svf文件中描述的一致,所以可以通过.jbc文件的编程波形(由逻辑分析仪捕捉得到)分析、修改自己的代码
NOTE:文章末尾有部分.jbc运行编程时测得的波形文件(由方案一得到,逻辑分析仪软件为KingstVIS,方案一的波形与quratus II直接下载.jbc文件的波形主要区别于IDLE状态下,方案一中TCK为低,quartus一直运行TCK)

由KingstVIS逻辑分析仪得到的.jbc编程波形

步骤一:
提取svf文件中的数据存到对应数组,分别存到命令数组、数据数组、TCK数组、TDI数组、TDO数组、MASK数组中

#define Get_CMD(x)    cmd_arry[x]
#define Get_DATA(x)   data_arry[x]
#define Get_TCK(x)    tck_arry[x]
#define Get_TDI(x)    tdi_arry[x]
#define Get_TDO(x)    tdo_arry[x]
#define Get_MASK(x)   mask_arry[x]

步骤二:
匹配对应命令,然后指令对应指令

//成功返回0 
//错误代码:
//1:Excute_SIR
//2:Excute_SDR
//3和4:输出与预期值不符合
BYTE Jtag_Excute(void){
	DWORD tck=0,cmd_index=0,data_index=0,tck_index=0,tdi_index=0,tdo_index=0,mask_index=0;
	DWORD cmd_size= CMD_FILE_SIZE;
	JtagGpioInit();
	while(cmd_size--){
		//提取命令
		switch(Get_CMD(cmd_index++)){
			case RESET_CMD:
				CurState = JBIRESET;
				Set_JTAG_State_Machine(JBIRESET); 
				delay_us(1000);
				break;
			case IDLE_CMD:
				Set_JTAG_State_Machine(IDLE);
				break;
			case RUN_TCK:
				if(Get_TCK(tck_index) == 50000) tck = 500003;
				else tck = Get_TCK(tck_index);
				delay_us(tck);
				tck_index++;
				break;
			case RUN_IDLE_TCK:
				Set_JTAG_State_Machine(IDLE);
				if(Get_TCK(tck_index) == 50000) tck = 500003;
				else tck = Get_TCK(tck_index);
				delay_us(tck);
				tck_index++;
				break;
			case SIR_CMD:
				if(JBISUCCESS != Excute_SIR(Get_TDI(tdi_index++),Get_DATA(data_index++))) return 1; 
				break;
			case SDR_DIR:
				if(JBISUCCESS != Excute_SDR(Get_DATA(data_index++),Get_TDI(tdi_index++),0,0)) return 2;
				break;
			case SDR_TDO:
				TDO_DATA = Get_TDO(tdo_index++);
				if(JBISUCCESS != Excute_SDR(Get_DATA(data_index++),Get_TDI(tdi_index++),1,0)) return 3;
				break;
			case SDR_TDO_MASK:
				TDO_DATA = Get_TDO(tdo_index++);
				TDO_MASK = Get_MASK(mask_index++);
				if(JBISUCCESS != Excute_SDR(Get_DATA(data_index++),Get_TDI(tdi_index++),1,1)) return 4;
				break;
			default:
				break;
		}
	}
	Set_JTAG_State_Machine(IDLE);
	Set_JTAG_State_Machine(JBIRESET); 
	printf("CPLD 代码升级成功\r\n");
	return 0;
}

NOTE:方案一源码占用资源非常多,而且代码量非常大,方案二几乎不占用RAM资源,而且真正的代码就只有一百多行,非常便于理解,同样非常适用于RAM资源紧张的MCU中。

资料总结:
MCU模拟JTAG烧写CPLD固件的文档资料:https://download.csdn.net/download/weixin_42518229/12912882

Altera CPLD升级官方Demo 移植到STM32F103ZGT6工程
https://download.csdn.net/download/weixin_42518229/18944029

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 36
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值