《电子技术应用》
您所在的位置:首页 > 嵌入式技术 > 业界动态 > 基于JTAG的DSP外部FLASH在线编程与引导技术

基于JTAG的DSP外部FLASH在线编程与引导技术

2008-10-14
作者:刘德生 李 杰

  摘 要: 介绍了DSP—FLASH在线编程" title="在线编程">在线编程(ISP)与引导系统的硬件构成,给出了创建可引导文件的步骤和实现FLASH存储器在线编程的算法;在AD公司Visual DSP++3.5集成开发环境下,通过JTAG对ADSP—21065L外部FLASH 存储器AT29LV020实现在线编程,并完成系统的引导。
  关键词: JTAG FLASH 在线编程 引导 Visual DSP++3.5


  在以DSP为核心的数字信号处理系统中,通常将可执行代码存放在非易失性存储器" title="非易失性存储器">非易失性存储器中,在系统加电或复位时通过DSP的引导加载" title="加载">加载(Boot Loader)机制将该代码转移到高速存储器中执行。AD公司出品的ADSP SHARC系列DSP内部的非易失性存储器因其资源有限,必须在外部加以扩展。FLASH存储器具有容量大、单电源供电和可在线编程的特点,是一种非常理想的存储器。
  若采用烧录器对FLASH存储器进行编程,则在修改程序时必须拔插器件,而某些表贴封装(如PLCC封装和TSOP封装)的器件又需要专用的转接插座,这使得程序的调试和参数的修改非常繁琐,而且容易对器件造成物理损伤。采用在线编程的方式对FLASH存储器进行操作,可以克服上述问题,为调试者提供了极大的方便。本文以ADSP—21065L外部扩展的FLASH存储器AT29LV020为对象,在Visual DSP++3.5环境中通过JTAG仿真器运行一段程序,将可引导代码在线烧录到FLASH中,并实现系统的引导。
1 在线编程与引导系统
  本系统以ADSP—21065L及外部的FLASH存储器AT29LV020为核心,由DSP控制FLASH存储器的擦除和读写。
  AT29LV020是用单电源3.3V供电的低功耗FLASH存储器,容量2MB(256K×8),8位数据总线,18位地址总线。该芯片以扇区(SECTOR)为基本的编程单位,共有1024个扇区,每个扇区包含256个字节。芯片的存储空间中包含两个引导区,分别是最低8K(0x00000~0x01FFF)和最高8K(0x3E000~0x3FFFF)的引导区[1~2]。
  系统引导时,DSP将FLASH作为普通的外部数据存储器,通过DMA方式访问。ADSP—21065L的外部地址空间为0x00020000~0x03FFFFFF。FLASH的物理地址(ADD)对于DSP来说就是(0x00020000+ADD)。整片AT29LV020占据ADSP—21065L的外部地址空间范围为0x00020000~0x0005FFFF,这段空间属于Bank0。访问该段空间时,DSP引脚有效。引导时,DSP引脚有效。所以,使用的组合作为FLASH的片选信号。DSP与FLASH的连接如图1所示[3]


2 DSP可引导文件的创建
  在线编程的过程如下:
  (1)创建一个适合FLASH存储器的引导程序" title="引导程序">引导程序文件A;
  (2)在Visual DSP++ 3.5环境中编写一个FLASH的操作程序,创建一个可执行的“.DXE”文件B;
  (3)通过基于JTAG的Emulator将B下载到DSP中执行,将A文件写入FLASH中。
  下面介绍如何在Visual DSP++ 3.5的开发环境中创建一个可以引导的文件[4]。该文件就是通过JTAG写入FLASH中的目标文件。具体步骤如下:
  (1)创建一个将要写入FLASH的源程序,在Visual DSP++环境中直接通过Emulator下载到DSP中执行,验证程序的正确性。
  (2)打开菜单Project→Project Options…,在Project标签的页面里,选择Type为Loader File;在Load标签的页面里,选择Boot Mode为Prom,选择Boot Format为ASCII,并为将要创建的.LDR文件指定名称。
  (3)重新编译工程,在工程目录中得到一个载入文件*.LDR。
  至此,一个可引导的文件就创建成功了。该文件的格式如下:
  ……
  0x1254
  0xCDF3
  0x256C
  ……
  该文件有n行,每行为一个双字节的16进制数。考虑到FLASH的数据总线是8位,在写入之前,必须将每行分成两个单字节的16进制数。
3 FLASH在线编程的实现
3.1 FLASH扇区编程的实现

  AT29LV020的操作包括扇区编程、整片擦除、读芯片ID、退出读芯片ID、引导区加锁等,这里关心的主要是扇区编程。
  扇区是AT29LV020编程的最小操作单位,每次编程操作时,目标扇区的256个字节同时进行。在DSP的写指令字序列的作用下,同一个扇区的256个字节被写入FLASH内部的缓冲区,然后FLASH自动启动编程操作。DSP向缓冲区写入同一个扇区的数据时,数据的写入顺序是任意的,但是相邻的写信号间隔不能大于150μs,否则将被视为写入操作完成,编程过程立刻启动,而扇区内没有写入内容的地址将全部被编程为FF。完成一个扇区的编程最多只需要20ms。编程过程启动后首先会自动擦除需要编程的扇区,所以在编程前并不需要对扇区进行单独的擦除操作。
  为了防止FLASH中的内容被误操作或者其它操作修改,FLASH默认为写保护状态。每次对扇区进行编程前必须写入一个命令字序列,才可以向FLASH的缓冲区写入数据,进而启动编程。编程结束后,FLASH自动恢复到写保护状态。
  一个扇区编程是否结束,可以通过以下三种方法判断:
  (1)反复读最后写入的地址的内容,如果编程没有结束,读到数据的最高位与最后写入的数据的最高位始终互为补码;编程结束后,读到的数据与最后写入的数据相等。
  (2)反复读任意某个地址的内容,如果编程没有结束,每次读操作都会导致次高位发生跳变;编程结束后,读到的结果就是写入该地址的实际数据。
  (3)写完一个扇区后延时20ms,作为扇区编程结束的依据。
  扇区编程的流程图如图2所示。


3.2 FLASH文件在线编程的实现
  考虑到AT29LV020的最小编程单位为一个扇区,首先应该将待编程的文件分割为若干个256字节的编程单元,对于最后的一个单元,无论是否够256字节,都无需理会,仍旧按照一个扇区处理。
  假设待编程的文件名为filename.ldr,采用汇编语言编写软件时,使用变量定义:
  .var f_data[ ] = 'filename.ldr';
  缓冲区f_data[ ]的首址指向filename.ldr的首行,f_data的每个元素都对应文件的一行。由于创建的引导程序文件每行数据都是16位的,包含两个8位字节,所以必须将其分解为两部分后分别写入FLASH。
  软件的流程如图3所示。


4 测试实例
  下面是将文件写入FLASH的完整程序,在实际中已经调试成功。通过该程序将一段闪灯代码blink.ldr写入FLASH中,复位后,被写入的代码自动加载到DSP中执行。在编程过程中,ADSP-21065L的FLAG10引脚输出周期为40ms的方波;编程结束后,FLAG8输出周期为40ms的方波。
  // 宏定义与变量初始化
  #define f_size 1572      //文件的行数
  #define mem_offset 0x020000 //FLASH的地址偏移
  #define u_mem1_a 0x025555 //命令字写入地址1
  #define u_mem2_a 0x022AAA //命令字写入地址2
  #include <def21065L.h>
  .section/dm seg_fout;
  .var f_data[] =“blink.ldr”;   //待写入的代码文件
  .section/dm seg_dmda;
  .var d_byte;
  .var addr;
  .var line_num = 0;     //当前扇区已写入行数
  .var byte_size;       //待写入代码字节数-1
  .var counter = 0;       //延时的计数值
  // 复位中断
  .section/pm pm_rsti;
  nop;
  jump start;
  nop;
  //以下是主程序
  .section/pm seg_pmco;
  start:
  nop;
  bit clr mode1 0x00001000; //屏蔽所有中断
  IRPTL = 0x0;     //清除未响应中断
  r0 = 0x0050;     //设置 FLAG10 和
  dm(IOCTL) = r0;     //FLAG8为输出引脚
  program:
  i0 = f_data;
  r2 = 0x0;     //已经写入的字节数-1
  r3 = f_size;
  r4 = r3 + r3;
  r4 = r4 - 1;
  dm(byte_size) = r4;
  r6 = dm(line_num);
  r7 = 0;
  comp(r6,r7);     // 判断是否为新的扇区
  if ne jump sect_load; // 不是,则直接向FLASH
         //缓冲区写入字节
  sect_ulock:       //是,首先写命令字序列
  r12 = 0xAA;
  dm(u_mem1_a) = r12;
  r12 = 0x55;
  dm(u_mem2_a) = r12;
  r12 = 0xA0;
  dm(u_mem1_a) = r12;
  sect_load:
  r0 = dm(i0,1);     //读取一行数据
  r1 = fext r0 by 0:8; // 获得低字节
  dm(d_byte) = r1;
  dm(addr) = r2;
  call load_byte;   //向FLASH写入低字节
  r2 = r2+1;
  r1 = fext r0 by 8:8;   //获得高字节
  dm(d_byte) = r1;
  dm(addr) = r2;
  call load_byte;     //向FLASH写入高字节
  r8 = dm(byte_size);
  comp (r2,r8);    //判断文件是否全部写完
  if eq jump done;   //是,则结束
  r6 = dm(line_num); //否,判断扇区是否结束
  r6 = r6+1;
  dm(line_num) = r6;
  r7 = 128;
  comp (r6,r7);
  if lt jump prog_loop; //否,继续向该扇区写数据
  sect_done:     //是,等待20ms
  nop;
  call wait_DQ7;
  ustat2 = dm(IOSTAT);
  bit tgl ustat2 FLG10O;
  dm(IOSTAT) = ustat2;   //翻转FLAG10
  r6 = 0;
  dm(line_num) = r6;
  r2 = r2+1;
  jump sect_ulock;   //开始向新扇区写数据
  prog_loop:
  r2 = r2+1;
  jump sect_load;
  done:         //编程结束
  nop;
  call wait_DQ7;
  ustat2 = dm(IOSTAT);
  bit tgl ustat2 FLG8O;   //翻转FLAG8
  dm(IOSTAT) = ustat2;
  jump done;
  load_byte:         //写字节子程序
  i4 = dm(addr);
  m4 = mem_offset;
  r12 = dm(d_byte);
  dm(m4,i4) = r12;
  rts;
  nop;
  wait_DQ7:         //20ms延时子程序
  r0 = dm(counter);
  r0 = r0+1;
  dm(counter) = r0;
  r1 = 0x59000;
  comp(r0,r1);
  if lt jump wait_DQ7;
  r0 = 0;
  dm(counter) = r0;
  rts;
  nop;
  上面的程序是针对由ADSP-21065L和AT29LV020构成的磁悬浮数字控制系统编写的,可行性与可靠性已经在实际应用中得到验证。该程序具有良好的可移植性,稍作修改即可用于类似的在线编程系统,具有较强的实用价值。
参考文献
1 Application Note: Atmel AT29 Flash Memories [Z]. Atmel Corporation, 1998.10
2 Data Sheet: 2-megabit (256K x 8) 3-volt Only Flash Memory AT29LV020 [Z]. Atmel Corporation, 2002.5
3 Engineer To Engineer Note: Interfacing Byte Programmed Flash Memories to the ADSP-2106x SHARC series [Z]. Analog Device Inc., 1999.7
4 刘书明,罗军辉. ADSP SHARC系列DSP应用系统设计[M]. 北京:电子工业出版社,2003.2

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。