通过MCU/ARM/CPU在线加载 Lattice CPLD/FPGA

LATTICE-CPLD/FPGA的在线加载程序包含7个文件,程序在安装目录下
1)debug.h
定义状态机操作中各个命令的字符串
2)hardware.h
定义硬件资源
3)hardware.c
和硬件操作相关的代码
4)ispvm_ui.c
和用户接口相关的代码
5)ivm_core.c
JTAG状态机操作代码
6)vmopcode.h
定义状态机操作中各个命令
7)IEEE1532.c
用于CRC校验

下图是这个代码包在我电脑中的位置。
MCU/ARM/CPU通过模拟JTAG在线加载 Lattice CPLD/FPGA

注意在新版的diamond安装目录下没有只有4个文件,是因为有一些文件内的代码移到ivm_core.c里面,但仍然基本上可以照搬本文进行操作。

因为这套代码是用于PC机的所以,移植到我们的系统中必须作些改动,我们需要改动的代码主要有:
1)hardware.h
在这里定义我们使用的硬件管脚资源。
2)hardware.c
修改writePort(),readPort,ispVMDelay()三个函数
修改包含的头文件
3)ispvm_ui.c
修改接口函数,可以自己封装ispVM()函数,但是建议修改原有的main()函数
4)vmopcode.h
将READ,LOCAL两个宏定义改个名字。

1. 文件的修改

1.1 修改hardware.h

CPLD/FPGA的加载使用5根信号线,分别是TDI,TDO,TMS,TCK和CE。在hardware.h中的定义的管脚有7根分别是pinTDI,pinTCK,pinTMS,pinENABLE,pinTRST,pinCE, pinTDO。我们使用pinTDI,pinTCK,pinTMS,pinCE, pinTDO这5个。

需要注意的是pinTDI,pinTCK,pinTMS,pinCE, pinTDO只是用来标记管脚的名字,不是一定要把他们定义成PD10等,当然你也可以这样做。

所以这里有两种方案:
1)管脚名定义和实际管脚一致

#define    pinTDI       PD10
#define    pinTCK       PD8
#define    pinTMS       PD9
#define    pinCE        PD4
#define    pinTDO       PD11

2)管脚名和实际管脚分开定义

#define pinTDI       (1<<0)     
#define pinTCK       (1<<1)
#define pinTMS       (1<<2)
#define pinCE        (1<<3)
#define pinTDO       (1<<4)      
#define PIN_TDI       PD10
#define PIN_TCK       PD8
#define PIN_TMS       PD9
#define PIN_CE        PD4
#define PIN_TDO       PD11

定义不同,writePort和readPort的实现不同。

1.2 修改hardware.c

该文件封装了对硬件的操作,主要集中在三个函数上writePort,readPort,ispVMDelay。
writePort是写端口操作,有两个参数第一个是管脚,第二个是电平。需要注意的在V8.1下一次写操作可能操作多个管脚。这就是为何上面对管脚的定义是
#define pinTMS (1<<2)
而不是
#define pinTMS 3

在V10.0下好象没有一次操作多个管脚。第二个参数的值为(0x00,0x01)。
readPort是读端口操作,没有参数,只要对TDO的读取。
ispVMDelay是延时函数,有一个参数–延时的时间。需要注意的是该参数的高两位是量度(在V8.1下是最高位),当最高两位为0B11时,表示参数是毫秒,当最高两位为0B00时,表示参数是微秒。在函数中的延时以毫秒为单位,不到一毫秒,延时一毫秒。
hardware.c中包含了许多头文件,其中有些是windows操作系统的头文件,我们必须将其替换成vxworks的头文件

/*
#include <windows.h>
#include <mmsystem.h>
#include <dos.h>
#include <malloc.h>
#include <conio.h>
*/
#include <vxworks.h>
#include <loglib.h>

1.3 修改ispvm_ui.c

在这个接口文件中,提供了一个加载函数ispVM(char filename ),但是不提倡使用,因为该函数中没有提供CRC校验。在该文件中还有一个main(int argc, char argv[])建议修改该函数,作为我们的在线加载函数,因为其中提供了IEEE1532标准的CRC校验。

1.4 修改vmopcode.h

在该文件的宏定义中有两个宏定义READ,LOCAL这两个宏定义在编译时发现和vxworks的定义冲突,所以必须将这两个宏定义的名字修改,建议改为

#define LOCALL
#define READD

1.5 修改函数返回值

char  ispVM(char *);
char  ispVMShift(char Code);
char  ispVMAmble(char Code);
char  ispVMLoop(unsigned short loop_cnt);

这几个函数的返回值类型为char。在实际测试中发现当文件不存在,文件错等异常测试中,都打印出成功信息。经过代码分析,在这些函数中当返回值为0时成功,当失败时返回代表失败的负数(如-1,代表加载文件校验错),但是函数返回后这些数变成正数(如255)。所以打印出成功信息。

所以将这几个函数的返回值类型改为int,且将

int ispVM(char *filename )
  {
   char  rcode; //改为 int rcode
   。。。
   }

该问题解决,可以正确检查
1)CRC校验错
2)找不到文件
3)文件类型错
4)文件错
5)参数错
五种错误。

代码中和延时相关的部分:
修改后的代码:

/****************************************************************************

                        ispVMDelay                              
 Users must devise their own timing procedures to ensure the specified
 minimum delay is observed when using different platform.
 The timing function used here is for PC only by hocking the clock chip. 
*****************************************************************************/
void ispVMDelay(unsigned short int delay_time)
{
    unsigned int current_time = 0, start_time = 0;

    if (delay_time & 0xA000)
    {
        /*check if in milliseconds*/
        delay_time &= ~0xA000;
        delay_time = delay_time * 1000;
    }

    if (delay_time > 0)
    {
        TMBDelay(delay_time);
    }
    else
    {
        for (start_time = 1; start_time <=10; start_time++)
        {
            current_time++;
        }
    } 
}

说明:
这个函数原来应该是采用for循环延时,我们修改为对PPC的TIMEBASE计数来延时。输入参数是1,就是1各微秒 ;

使用情况:
在原来代码的以下地方使用:
a. 在文件IVM_Hardware.c中的以下函数:

void ispVMEnd(void)
{
 ispVMStateMachine(RESET);   /*step devices to RESET state */
 ispVMDelay(1);              /*wake up devices*/       //延时1us(我加的说明)
 writePort(pinCE,0x00);  /*disable the Lattice Cable*/
}

插入1微秒延时。

b. 在IVM_CORE.C中的以下函数:

/****************************************************************************
                     ispVM Shift                            
 Perform the function of SIR, SDR and XSDR. It is to shift instruction or
 Data into TDI and/or out of TDO.  
 global:
    DataSize----------The size (bits) of the data or instruction to process.                  

 Input                                                          
     Code---------------SIR,SDR or XSDR      
 Return                                                         
     rcode--------------pass or fail

*****************************************************************************/
int ispVMShift(char Code)
{
 int i;
 int j;
 int rcode;

 rcode=0;
 DataSize = ispVMDataSize();
#ifdef DEBUG
 printf("bits size=%d\n",DataSize);
#endif

 DataType &= ~(SIR_DATA+EXPRESS+SDR_DATA);   /*clear the flags first*/
 switch (Code) {
    case SIR:   /*shift instruction stream into devices ...
(更多...)
编辑 重设标签(回车键确认) 标为违禁 关闭 合并 删除

提问于 2018-01-12 20:52:47 +0800

这个帖子被标记为一个社区wiki

这个帖子是一个wiki(维基). 任何一个积分 >500的人都可以完善它