一只鱼's profileEE小站PhotosBlogListsMore Tools Help

一只鱼 我是

Occupation
Interests

EE小站

为生计奔波的工程师的梦想后花园
本站百度空间镜像
本站SkyDrive空间

■ 在本站的SkyDrive里有为cygwin和linux编译的arm-linux-gcc-4.1.0、arm-softfloat-linux-gcc-3.4.5和arm-linux-insight-6.8(包括arm-linux-gdb-6.8)
■ MPC8313e的事情先暂停。
October 10

Mum计划之urjtag、gdbproxy的下载速度优化

 
国庆假期宅在北京,下回放假一定要出去走走。不过也有收获,就是今天这篇文章。
本文的主要内容是如何修改urjtag和gdbproxy的代码,提高Blackfin GDB调试时,代码下载的速度。
本文属于Mum计划,Mum计划的目的是制作一套开源的Blackfin调试和开发解决方案。
Mum计划使用基于FT2232的JTAG电缆——MumJTAG进行Blackfin处理器的GDB调试。
MumJTAG使用urjtag和gdbproxy来进行GDB调试:urjtag和gdbproxy的基本编译请看这篇文章:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!850.entry
本文隐含性的提到JTAG调试原理知识,如果不明白,请自行查找文章。
本文参考文档有,http://blackfin.uclinux.org上的这两篇:
还有http://www.hjtag.com的Twentyone大侠写的一篇,我给放到EE小站的SkyDrive了:
关于DCC下载,请看http://blackfin.uclinux.org上的这篇:
以及ADI官方的Blackfin手册,我下载下来,放到EE小站的SkyDrive:
下面开始正题,转载请注明来自我是一只鱼的EE小站,邮件cosine@126.com
 
虽说之前我成功编译了Blackfin的GDB调试代理,但用起来可不像OpenOCD那么好用,尤其是gdbproxy的代码下载速度仅有4kb/s,一个u-boot就要一分钟才能下载完,简直无法接受。为了让Mum计划的调试方案实用,我付出了很多努力。虽然我没有深究Blackfin JTAG调试原理,但我的代码勉强让gdbproxy的代码下载速度提高到了40~60kb/s,虽然比不上有人专门研究的可以达到120kb/s的ICEBear(http://www.section5.ch/icebear),但是作为开源调试器,60kb/s的下载速度应该可以对付大多数应用了,我就偷点懒,不继续优化,就让ICEBear有点钱赚。微笑同时,由于我是囫囵吞枣式的做了这个优化,肯定有很多不合理之处,请真正牛叉的大侠予以指正,谢谢。
 
为什么urjtag和gdbproxy那么慢呢?因为FT2232这种器件仅仅是一个信号转换器,所有的JTAG操作都是用程序模拟的。FT2232是USB的,这就带来一个问题,USB数据传输不是实时的,每个设备都占用一定的轮询时间;如果要从JTAG读取某些东西,就必须以轮询周期为单位读取。例如,gdbproxy每向JTAG写4个字节(unsigned long),就要读取JTAG状态,看是不是CPU准备好了。由于USB的轮询周期较长,说实话我也不记得了,也许是125us,也许是1ms,那么这个周期写一下数据,下个周期读一下状态,下载速度就只能是个位数的kb了。
 
说说我是怎么做到的:
1.将默认JTAG TCK频率提高到6MHz;
2.实现传说中的DCC下载功能;
3.关闭大于4字节批量写操作的Cache清空功能。
 
第一点没有什么说到的,很好理解。
第二点,什么是DCC下载?DCC这个名字其实借用了ARM公司的说法(Debug Communication Channel),ADI有别的叫法,不管怎么叫,他们描述的事实是一致的——CPU和JTAG扫描链共享某个寄存器。说说DCC下载怎么工作吧,CPU运行一段小程序,不断扫描JTAG共享的寄存器里是不是有新数据,如果有,就保存到内存中;JTAG电缆不断通过JTAG口,向JTAG共享寄存器里写入新数据。由于现代CPU的读取和保存数据速度一般都比JTAG扫描链快很多,所以JTAG电缆就不需要看CPU是不是准备好了,节约了读取CPU状态的时间。这里还牵涉到两个问题:(1)如果不使用DCC下载,是什么样子?(2)为什么节约读取CPU状态的时间就能提高速度?问题(1),不使用DCC下载,CPU的JTAG调试逻辑里一般都有一个仿真指令寄存器(Emulation Instruction Register),用JTAG可以向这个寄存器里写入单条处理器指令,例如对于ARM,可以是MOV R0, 0x00之类的,并执行,这样,R0的数值就变成0了,再写入STR R1, R0之类的指令,就把数据存到内存去了,但对于Blackfin,这样需要查询CPU是不是完成了仿真指令。问题(2),刚才提到了,USB的轮询周期时间太长,FT2232内部有FIFO,可以储存4k个的JTAG信号电平变换的时序数据,也就是说,如果不接收,只发送,那么每当JTAG电平数据达到4k个的时候才需要发送一次,这样一次发送就大约可以发送几十个字节,而不是原先的4个字节;再说接收造成的影响,由于每个USB的轮询周期,数据既有读,又有写,如果某个周期必须读一次数据,而写数据没有那么多,就造成了FT2232内部FIFO不能被填满,浪费了时间。呵呵,很复杂。
DCC下载的使用是有代价的——需要一个很小的内存空间来跑CPU DCC扫描程序。也就是说,先通过JTAG下载一段小程序到CPU的SRAM,然后运行这段小程序来下载代码。在我这个优化里,我使用了0xffa08000~0xffa08020这段32字节的空间,这段空间BF531~533都有。我写的CPU DCC扫描程序很简单:
    P1.L = LO(DBGSTAT);
    P1.H = HI(DBGSTAT);
    R1.L = 0x0002;
    R1.H = 0x0000;
.loop_dbgstat:
    R0 = [P1];
    R0 = R0 & R1;
    cc = R0 == R1;
    if cc jump .write_emudat;
    jump .loop_dbgstat;
.write_emudat:
    R0 = EMUDAT;
    [P0++] = R0;
    jump .loop_dbgstat;
需要做的就是启动DCC之前,保护R0、R1、P0、P1和PC,并把R0设成要下载数据的首地址;在执行程序之后,还原被保护的寄存器。
第三点,我是自作主张的,因为我觉得一般执行load命令的时候才会有大量的数据写入,而load命令执行之后,本身程序就要重启,跟cache没有什么关系,所以无所谓。
 
原理说明白了,下面贴上程序:
 
  • urjtag/src/bfin/bfin.c,982行,增加函数

void
part_emudat_set_new (chain_t *chain, int n, uint32_t value, int exit)
{
  part_t *part;
  tap_register *r;

  assert (exit == EXITMODE_UPDATE || exit == EXITMODE_IDLE);

  if (part_scan_select (chain, n, EMUDAT_SCAN) < 0)
    return;

  part = chain->parts->parts[n];
  r = part->active_instruction->data_register->in;
  emudat_init_value (r, value);
  chain_shift_data_registers_mode (chain, 0, 1, exit);
}

  • gdbproxy/target_bfin_new.c,464行

static char default_jtag_connect[] = "cable gnICE";

修改为

static char default_jtag_connect[] = "cable USB-to-JTAG-IF ftd2xx-mpsse 0725:6010";
static char default_jtag_frequency[] = "frequency 6000000";

  • gdbproxy/target_bfin_new.c,1258行,增加函数

static void
core_emudat_set_new (int core, uint32_t value, int runtest)
{
  part_emudat_set_new (cpu->chain, core, value,
     runtest ? EXITMODE_IDLE : EXITMODE_UPDATE);
}

  • gdbproxy/target_bfin_new.c,3085行,函数修改为

static void
cache_flush (int core, uint32_t addr, int size)
{
  uint32_t p0;
  int i;

  assert (size > 0);

  if (size <= 4)
  {
   p0 = core_register_get (core, REG_P0);

   core_register_set (core, REG_P0, addr);
   core_dbgctl_bit_set_emuirlpsz_2 (core, UPDATE);
   for (i = (size + addr % CACHE_LINE_BYTES - 1) / CACHE_LINE_BYTES + 1;
        i > 0; i--)
     core_emuir_set_2 (core, gen_flush (REG_P0),
         gen_iflush_pm (REG_P0), RUNTEST);
   core_dbgctl_bit_clear_emuirlpsz_2 (core, UPDATE);

   core_register_set (core, REG_P0, p0);
  }

  • gdbproxy/target_bfin_new.c,3409行,函数修改为

static int
memory_write (int core, uint32_t addr, uint8_t *buf, int size)
{
  uint32_t p0, r0, p1, r1, pc;
  int clobbered[BFIN_DCPLB_NUM];
  int i;
  uint8_t isram_backup[32];

  assert (size > 0);

  p0 = core_register_get (core, REG_P0);  //保护各个寄存器
  p1 = core_register_get (core, REG_P1);
  r0 = core_register_get (core, REG_R0);
  r1 = core_register_get (core, REG_R1);
  pc = core_register_get (core, REG_RETE);

  for (i = 0; i < BFIN_DCPLB_NUM; i++)
    clobbered[i] = 0;

  dcplb_validate_clobber_p0r0 (core, addr, size, clobbered);

  core_register_set (core, REG_P0, addr);

  core_dbgctl_bit_set_emuirlpsz_2 (core, UPDATE);

  if ((addr & 0x3) != 0)
    core_emuir_set_2 (core,
        gen_move (REG_R0, REG_EMUDAT),
        gen_store8pi (REG_P0, REG_R0), UPDATE);

  while ((addr & 0x3) != 0 && size != 0)
    {
      core_emudat_set (core, *buf++, RUNTEST);
      addr++;
      size--;
    }
  if (size == 0)
    goto finish_write;

  if (size >= 4)
 {
   bfin_resume_from_addr(0, 0, 0xffa08000);  //启动已经储存在0xffa08000的CPU DCC扫描程序

   for (; size >= 4; size -= 4)
   {
    uint32_t data;
  
    data = *buf++;
    data |= (*buf++) << 8;
    data |= (*buf++) << 16;
    data |= (*buf++) << 24;
    core_emudat_set_new (core, data, RUNTEST);  //往共享寄存器里写数据
   }
 
   bfin_stop();  //停止CPU DCC扫描程序
 }

  if (size == 0)
    goto finish_write;

  core_emuir_set_2 (core,
      gen_move (REG_R0, REG_EMUDAT),
      gen_store8pi (REG_P0, REG_R0), UPDATE);

  for (; size > 0; size--)
    core_emudat_set (core, *buf++, RUNTEST);

finish_write:

  core_dbgctl_bit_clear_emuirlpsz_2 (core, UPDATE);

  dcplb_restore_clobber_p0r0 (core, clobbered);

  core_register_set (core, REG_P0, p0);  //恢复各个寄存器
  core_register_set (core, REG_P1, p1);
  core_register_set (core, REG_R0, r0);
  core_register_set (core, REG_R1, r1);
  core_register_set (core, REG_RETE, pc);

  return 0;
}

  • gdbproxy/target_bfin_new.c,4318行,增加:

  char *freq_string = default_jtag_frequency;

  • gdbproxy/target_bfin_new.c,4342行,增加:

    {"freq", required_argument, 0, 18},

  • gdbproxy/target_bfin_new.c,4520行,增加:

 case 18:
  strcpy(freq_string, "frequency ");
  strcat(freq_string, optarg);
  break;

  • gdbproxy/target_bfin_new.c,4569行,增加:

 jtag_parse_line (chain, freq_string);

  • gdbproxy/target_bfin_new.c,5061行,增加:

  uint32_t dcc_code[] =
  {
   0x5008e109,
   0xffe0e149,
   0x0002e101,
   0x0000e141,
   0x54089108,
   0x18020808,
   0x31c72ffc,
   0x2ff99200,
  };  //CPU DCC扫描程序机器码
  
  bfin_write_mem(0xffa08000, (uint8_t *) dcc_code, 0x20);

 还有一个值得说的是,http://blackfin.uclinux.org上最新的urjtag源码中使用了strcasestr函数,这个函数在cygwin的gcc的glibc里面没有,编译无法通过。不过没有关系,可以自己写一个。

  • jtag/src/cmd/bfin.c,53行,增加:

#include <ctype.h>

#ifndef HAVE_STRCASESTR
char * strcasestr (char *haystack, char *needle)
{
 char *p, *startn = 0, *np = 0;

 for (p = haystack; *p; p++) {
  if (np) {
   if (toupper(*p) == toupper(*np)) {
    if (!*++np)
     return startn;
   } else
    np = 0;
  } else if (toupper(*p) == toupper(*needle)) {
   np = needle + 1;
   startn = p;
  }
 }

 return 0;
}
#endif

今天就写到这里。过一段时间我会放出整理测试后的源代码以及可执行文件,如果你觉得修改过程太过复杂,可以直接使用我写的代码。

September 22

关于J-Link GDBServer的BUG

 
发现J-Link GDBServer有个BUG,它不能获取CPSR的值,导致GDB条件执行语句的时候会把断点放在错误的位置,表现为条件执行语句有的时候不能单步——一单步就运行起来了。虽然我买的是盗版的J-Link,但我还是厚着脸皮到Segger的官网发帖子问了,嘿嘿。Segger反应用了17天的时间,我觉得还算及时,看这个地址:http://www.segger2.com/index.php?page=Thread&threadID=363
从J-Link 4.09b开始这个问题就解决了,我也试过了,如果大家遇到这个问题可以尝试更新下J-Link软件。

小述电磁兼容

 
我必须写点什么证明这个Blog还在我的维护之下,呵呵。
 
先赞一下我公司的领导,终于请专业咨询公司为我们进行了为期两天的电磁兼容知识的培训;收获还真的不小,困扰我很久的一些问题有了明确的理论答案,下面就要针对我的实际工作应用这些理论了,呵呵。
为了防止我自己忘记,同时也给需要的同学们提供个参考,我决定把这两天培训的要点和我工作以来的体会写下来。转载请注明来自我是一只鱼的EE小站,邮件cosine@126.com,欢迎有问题在此留言或来信交流。
 
  • 什么是电磁兼容

对于还没有毕业的、刚毕业的同学们可能对电磁兼容体会不深。但不论老师的指导、业界的传言,都给我们指出了一些电磁兼容的蛛丝马迹:每个IC加一个104电容、数字地模拟地需要分割等等。先不讨论这些做法的对错,至少说明,我们需要做些什么事情,才能保证我们的设计能很好的工作。
电磁兼容性(EMC)是描述一个电子设备的两方面性能:对别的设备的干扰严重程度(EMI)和对自然界或别的设备的干扰的抗受程度(EMS)。有很多很牛X的人做了很多很牛X的工作,用标准的形式把电磁兼容分成了若干个可以用测试衡量的项目,例如IEC61000-4-X系列;国标GB17626.X系列,就是抄IEC的。我不想像教课书一样给大家列出这些标准,就用几个简单的、我们经常能遇到现象来对应下:
1. 很多人遇到过把示波器地线夹到板子上的时候,板子复位的现象吧,这个是热插拔“浪涌(Surge)”的效果;
2. 冬天的时候,北方的同学们经常对自己的笔记本电脑或者台式机过电吧,这个是“静电放电(ESD)”干扰;
3. 使用电钻的时候听收音机,有杂音,这是“快速瞬变脉冲群(EFT)”的效果;
注意这几个用引号括起来的词,就是几个典型的电磁兼容测试项目。当然还有两个非常重要的项目“辐射”和“传导”,但我觉得只是为了让单板正常工作,这两个项目不用考虑;我目前也没有这方面的实践经验,本文就简略些。据我头说我们要买个频谱仪,有那个之后我再玩玩这两个项目,看看理论的东西是不是胡说。吐舌
再说说对电磁兼容的范畴界定:以我的认识,电磁兼容性应算产品的性能,不能划归可靠性范畴;因为可靠性主要研究产品能在什么应力下能用多久不坏,不关心干扰的问题。因此,电磁兼容性的提高,不代表可靠性提高,反而由于引入了串联的对策器件(这个词下面就解释了),对策器件选择不当会降低系统可靠性。但研究所、实验室科研就不用理清这个概念了,反正课题验收只要好使一次,没有人关心可靠性。
很多人觉得电子设计必须考虑电磁兼容各种规则,其实有些情况不用,或者说不用考虑全部;因为请一定记住,电磁兼容性的提高不是随便就能达到的,是有成本的,这包括几个方面:电磁兼容PCB设计往往要求高,层数和面积都会增大;增加对策器件;增加测试成本。山寨手机往往电磁兼容做的不好,但卖的好才是真的好。但对于工程师,必须懂得这些知识,中国人不能永远搞差异化产品的。呵呵,扯远了。

  • 重新认识PCB和基本器件

这个小节讲的全部是一件事情:分布参数。分布参数就是分布在PCB或者器件中的电容、电感、电阻,这些东西数值很小,但是在很多情况下,他们造成的影响狠严重。给出一个经验数值,一般1厘米长的PCB走线的电感量是6nH。按照经典的复阻抗计算公式Z=ωL,在100MHz下,1厘米导线的复阻抗达到3.76Ω,稍微长一些的导线对高频信号就会表现出很大的衰减。
而我们常用的电容、电感因为存在分布参数,在高频下也不能用简单的符号来表示。以电容的模型为例,请看我们常用的X7R型的0603封装50V耐压0.1μF电容的模型,其中L1和L2影响电容的等效串联电感(ESL),R1、R2、R3影响电容的等效串联电阻(ESR)。

 有这么多分布参数,导致这个104电容的复阻抗-频率曲线变成了这样:

 

可以看出,这种电容在11M左右的时候,复阻抗最小,大约为100mΩ。随后由于等效串联电感的存在,复阻抗会逐渐增大。但刚才已经提到了,1厘米的PCB走线有6nH的电感,当这种电容焊接在电路板上的时候,其复阻抗特性曲线会向左移动一些;所以,这种电容比较适合用于若干MHz到20MHz频率下的滤波。很多单片机的工作频率都在这个范围,因此104电容可以用于单片机系统的电源滤波。但如今的ARM、DSP、PowerPC系统频率都不下百兆,用104电容就不合适了。
说说等效串联电阻的作用:等效串联电阻小的电容,其复阻抗特性曲线整体下移,因此,在很大频率范围内复阻抗都很小,所以等效串联电阻越小的电容,滤波效果越好。

接下来说说电感,电感也存在等效串联电阻、匝间电容等分布参数。除了高频下,电感特性会变化之外,电感还受到直流电流的影响——因为电流会让电感的磁芯饱和。另外,有的磁芯磁导率还会受到温度的影响。用TDK公司的某电感的参数特性曲线为例子说明:

  •  认识电磁兼容对策器件

下面来说说专门为了电磁兼容而存在的器件。
主要可以分为滤波和瞬态抑制两个类别。起滤波作用的有:共模电感、磁珠、三端电容等;起瞬态抑制作用的有:TVS二极管、压敏电阻、气体放电管等。这些器件的原理、结构、基本作用等我不说了,百度一下一大片。说些不容易搜索到的:
1. 磁珠到底是什么
很多人搞不清楚磁珠、电感、0欧姆电阻的区别。先看看村田制作所(好多年了,一直觉得和春田花花幼儿园有关系吐舌)提供的磁珠内部结构:

原来就是用线在里面绕圈啊,可以肯定这和0欧姆电阻不一样,因为它有一定电感。那么磁珠和电感有什么区别呢?我觉得是磁心材料的区别,电感的磁芯材料是用来储能的,而磁珠的磁性材料是用来耗能的,在高频的时候产生很大的涡流,来把交变信号的能量消耗掉。所以,在高频下,磁珠表现出很大的纯电阻值,而不是复阻抗值。可以看看磁珠的阻值频率特性曲线:

那么,什么地方用磁珠呢?建议的应用是:电源滤波、信号滤波。强烈不建议将磁珠用于模拟、数字地之间的跨接,因为这样容易引起地电位差,对AD、DA的精度产生很严重的影响;这种情况用0欧姆电阻或者干脆不区分模拟和数字地,只区分模拟和数字电源。目前我尝试过两个地之间用磁珠有效的只有一种:防止热插拔时的浪涌。

2.TVS、压敏电阻、气体放电管到底用那个
这三个器件都是用来抑制瞬态电压变化的,不同的是TVS响应最快(0.1ns级别),但通流量小;压敏电阻响应比较快(1ns级别),通流量大;气体放电管响应慢(1us级别),通流量大。因此,TVS和压敏电阻可以用来抑制ESD放电,气体放电管和压敏电阻可以用来抑制浪涌。

  • 怎样提高电磁兼容性

之前我提出电磁兼容是产品的性能,但对于概念不清的人来说,“提高电磁兼容性”这个提法很模糊,只好通俗解释下——就是怎样通过电磁兼容测试。
请一定建立起这个概念:提高电磁兼容性要从板级设计开始。在产品的板级设计不太差的前提下,可以通过增加一些简单的电磁兼容对策器件实现电磁兼容性的提高——但这完全是治标不治本。给我上课的老师就举了某电力测量设备的制造商例子,他们的产品为了通过2kV的快瞬脉冲群,共模电感、Y电容的加了一大堆,还修改采样电路板PCB,搞得很麻烦;原因就在于他们的单片机系统设计太垃圾了。2kV的快瞬对低速的单片机系统来说就和玩一样,轻松对付。那么具体该怎么做呢,第一,要注意PCB和基本器件的分布参数,正确选择各种器件;第二,要了解各种电磁兼容对策器件的特性和选型方法;第三,注意各种滤波设计;第四,要注意PCB设计。前面两条已经在上文种有所涉及了,但我写出来的就是个导读,要是全写出来我干脆写书去了。说说后面两条。

  • 电磁兼容滤波设计

这个叫法和一般的信号滤波设计不同,是有针对性的。再次说明,本文不涉及产品对外辐射的控制,但这些滤波器一般可以起双向滤波的作用,通俗点说,里面的干扰出不来,外面的干扰进不去。
要设计这种有针对性的滤波器,首先必须了解将要面对的是什么信号:以快瞬脉冲群、浪涌、静电放电为例。
1.快瞬脉冲群
快瞬脉冲群是用来模拟感性负载在电路上的频繁接入和断开的情况,比如电机、继电器等。它的电压波形是这样的:

 

快瞬脉冲群可以加在电源上,如果AC/DC电源的传导衰减不够,就会在设备的直流电源上产生相似波形的干扰信号。快瞬脉冲也可以通过耦合夹耦合在信号线上耦合出相似波形的干扰信号,通过信号端口传入设备。另外,由于快瞬脉冲群的辐射能量很大,附近的线缆也会感应产生相似波形的干扰信号。如果是单个干扰脉冲,数字电路一般有施密特触发器,不会误触发。但连续的脉冲群会使施密特触发器失效,而扰乱数字电路。
快瞬脉冲群单个脉冲的上升沿,决定了其能量大致分布在十几MHz~几百MHz的范围内,因此滤波器在这个区间内要有滤波效果。
另外,快瞬脉冲群干扰是共模的,不论你选则的是L、N,L、PE,N、PE,L、N、PE那一种耦合方式,快瞬脉冲群都是共模的。有必要解释什么叫共模干扰,共模干扰指的是相对于某个共同的外部参考源,例如大地的干扰。我目前理解的脉冲群共模干扰的模型如下:

脉冲群的干扰就像河道里的水波一样,一波一波的涌入设备,如果被测设备完全悬空,那么仅仅是其电势被抬高,不会产生影响;但是,由于被测设备和大地之间存在耦合电容,高频干扰信号就能找到回流路径,因此,设备的正常工作受到影响。
对于脉冲群,可以使用如下图所示的对策:

我仅对电源线对策举例,信号线的对策大同小异。被测设备最好要有个金属屏蔽外壳,并与大地有良好的电气连接,这样PE信号的干扰就可以直接导入大地。交流供电线上的干扰使用共模电感抑制,注意应选择滤波区间在脉冲群能量频率范围内(十几MHz~几百MHz)的共模电感,通过共模电感之后共模干扰会大幅衰减,图中的箭头大小表示能量的大小。光有共模电感有些情况下还不够,还应在进线端增加对大地的Y电容,让干扰能量尽可能早的回流到大地,而不干扰到后级的电源模块和功能电路。

2.浪涌

浪涌就是模拟雷击的,当然还有热插拔浪涌,这个暂时不讨论。 浪涌测试的电压波形如下:

电流波形就不贴出了,长的和这个波形差不多。浪涌的特点是电流上升沿较缓,但峰值电流很大,可以达到数百到上千安培;同时,浪涌的电压较高,可以达到数千伏。浪涌能在很短的时间内令设备内部器件或空气击穿,损坏设备。由于浪涌的能量很大,完全堵住浪涌是不可能的;因此,浪涌的对策是疏导。在电源线上放置瞬态抑制器件,如TVS、压敏电阻、气体放电管等等。典型的对策电路如下所示:

这种形式的电路,放置在设备的电源输入端,一旦电源出现浪涌,压敏电阻和气体放电管就会导通,将浪涌能量导走,令其不进入后部处理电路。而在没有浪涌时,由于气体放电管几乎没有漏电流,可以满足安规要求。

3.静电

静电放电测试用来模拟人体对设备的放电。其波形如下图所示:

静电放电结合了脉冲群和浪涌的特点,由于静电放电电流上升沿非常陡峭,使放电时产生宽达数GHz的干扰频谱;另外静电放电的电压一般可以达到1万伏特,峰值电流可以达到数十安培,虽然放电的时间短、能量较小,但也有可能使设备损坏或造成可积累的损坏。静电的对策是脉冲群对策和浪涌对策的结合:一方面要加强屏蔽和共模滤波,另一方面也要对放电电流进行疏导,避免其进入电路。

  • 如何设计电磁兼容性良好的PCB

设计PCB学问就多而乱了,什么层叠设置,阻抗匹配,串扰预防等等等等。其实要提高电磁兼容性,最重要的原则是:回路面积最小。
回路面积最小指的是信号路径和回流电流路径所围成的截面积最小。用一个信号穿越地分割的例子来说明:

图中红色的是某双面板顶层信号线,蓝色是底层地平面。当信号线在完整的地平面上时,黄箭头所示的信号电流和绿箭头所示的信号回流电流基本重合,二者回路面积最小;当地平面存在分割时,回流电流就会绕开地平面分割行进,使回路面积增大。回路面积越大,电路感应出的干扰信号幅度也就越大,向外的辐射也越多。相关知识可以查看PCB方面书籍。
最符合回路面积最小原则的PCB设计是所有信号线都有完整地平面陪伴,最不符合的例子是电缆中独行的信号线。

PCB设计虽然没有太高的技术含量,但确是很需要经验的。

April 15

Mum计划之MumJTAG GDB代理程序编译——OpenOCD、urjtag和gdbproxy的编译


这篇文章主要是讲如何编译MumJTAG的ARM和Blackfin GDB调试代理程序的,如果你对GDB调试还没有什么概念,可以看这篇文章:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!268.entry。如果你想知道怎么使用OpenOCD进行ARM调试,请看这篇文章:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!485.entry。如果你想知道ARM上GDB调试怎么和Eclipse接口,请看这篇文章:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!602.entry

MumJTAG是我设计的一个JTAG调试电缆,它的制作请看这篇文章:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!786.entry

本文在Windows下用Cygwin环境,配合FT2232的D2XX驱动,成功编译了OpenOCD、urjtag和gdbproxy;换句话说,采用本文介绍的方法,可以在Windows下使用FTDI提供的驱动,使用FT2232电缆。OpenOCD在Cygwin下的编译没有什么难度,urjtag和gdbproxy的编译,因为没有找到类似的文章,我花了2天的时间……希望我的记录能给大家提供些方便,不要走我的弯路。转载请注明来自我是一只鱼同学的EE小站,邮件cosine@126.com

另外说一下,其实ADI提供了Windows环境下的gdbproxy,但是我试了下,不好使,也许是因为它用的是libftdi驱动的原因,我没有调查在Windows环境下怎么装libftdi驱动,因为我想绝大多数人会使用D2XX驱动吧。给出ADI工具链的地址:http://blackfin.uclinux.org/gf/download/frsrelease/392/5211/blackfin-toolchain-win32-2008R1.5.exe

  • OpenOCD的编译

这个很简单,大家可以看OpenOCD的手册:http://openocd.berlios.de/doc/openocd.pdf。我这里再啰嗦一遍。

先到OpenOCD的官方网站:http://openocd.berlios.de/,下载OpenOCD源代码:http://prdownload.berlios.de/openocd/openocd-0.1.0.tar.gz,假设保存为E:\Mum\OpenOCD\openocd-0.1.0.tar.gz。用命令行来说明:

$ cd /cygdrive/e/mum
$ tar xvzf openocd-0.1.0.tar.gz
$ mv openocd-0.1.0 openocd

当然也可以用svn下载OpenOCD最新的版本,在Cygwin的命令行中输入:

$ cd /cygdrive/e/mum
$ svn checkout svn://svn.berlios.de/openocd/trunk openocd
$ cd openocd
$ ./bootstrap

然后准备MumJTAG的D2XX驱动程序,可以看之前的这篇文章制作一个:http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!786.entry,或者到这里下载我做好的驱动:http://cid-4201fdc93932ddaf.skydrive.live.com/self.aspx/Mum%e8%ae%a1%e5%88%92/MumJTAG/MumJTAGDriver.rar,假设驱动程序存储在E:\Mum\MumJTAGDriver。现在可以编译了,还是用命令来说明。

$ cd /cygdrive/e/mum/openocd
$ ./configure --prefix=/cygdrive/e/mum/openocd/build --enable-ft2232_ftd2xx --with-ftd2xx-win32-zipdir=/cygdrive/e/mum/mumjtagdriver
$ make
$ make install

这样,OpenOCD就编译好,并拷贝到E:\Mum\OpenOCD\build里了。

为了让OpenOCD正常工作,还需要一个针对要调试的CPU的配置文件,这个配置文件的编写可以参考OpenOCD的手册。这里我给出我编写的MumJTAG连接AT91SAM9263的配置文件:

##########################
# Interface configuration
##########################

interface ft2232
ft2232_device_desc "MumJTAG A"
ft2232_layout "usbjtag"
ft2232_vid_pid 0x0725 0x6010
jtag_khz 8
reset_config trst_and_srst

##########################
# TAP configuration
##########################

jtag newtap at91sam9263 cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x0792603F
jtag_nsrst_delay 200000
jtag_ntrst_delay 200000

##########################
# Target configuration
##########################

set _TARGETNAME [format "%s.cpu" at91sam9263]
target create $_TARGETNAME arm926ejs -endian little -chain-position $_TARGETNAME -variant arm926ejs

# Internal sram1 memory
$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x00300000 -work-area-size 0x1000 -work-area-backup 1

##########################
# Port configuration
##########################

telnet_port 23
gdb_port 2331
tcl_port 6666

值得一提的是,不同JTAG电缆的ft2232_device_desc、ft2232_vid_pid是不一样的,应根据实际修改;ft2232_layout设定的是电缆的类型,OpenOCD支持很多种电缆的类型,MumJTAG兼容USB to JTAG Interface,所以写“usbjtag”;如果你自己独创了一种电缆,就要修改OpenOCD的源代码。假设将配置文件保存为E:\Mum\OpenOCD\build\AT91SAM9263.cfg,接下来连接MumJTAG到目标板的JTAG,给目标板上电就可以启动OpenOCD了,如下所示。

$ cd /cygdrive/e/mum/openocd/build/bin
$ ./openocd -f /cygdrive/e/mum/openocd/build/mumjtag.cfg
Open On-Chip Debugger 0.1.0 (2009-04-15-16:59) Release


BUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS


$URL: https://kc8apf@svn.berlios.de/svnroot/repos/openocd/tags/openocd-0.1.0/src
/openocd.c $
8 kHz
Info : JTAG tap: at91sam9263.cpu tap/device found: 0x0792603f (Manufacturer: 0x0
1f, Part: 0x7926, Version: 0x0)
Info : JTAG Tap/device matched

OpenOCD自带很多CPU和JTAG电缆的配置文件,在安装目录里,它的使用就不细说了,大家自己看手册。

  • urjtag和gdbproxy的编译

urjtag和gdbproxy是uclinux下的一个项目,由ADI官方派人维护。它是可以使用FT2232电缆通过JTAG调试Blackfin系列处理器的一套GDB调试服务程序。顺便提一下,FT2232电缆无法在ADI的Visual DSP++下使用。

urjtag和gdbproxy是一体的一套软件,他们必须一同编译,而且路径有要求,例如urjtag储存在E:\Mum\urjtag_gdbproxy\jtag,那么gdbproxy就必须储存在E:\Mum\urjtag_gdbproxy\gdbproxy。编译的顺序是先urjtag后gdbproxy。urjtag和gdbproxy的编译和使用可以参考blackfin.uclinux.org的wiki,地址是:http://docs.blackfin.uclinux.org/doku.php?id=toolchain:debug:gdbproxy

先到uclinux的官方网站下载urjtag和gdbproxy的源码,地址是:http://blackfin.uclinux.org/gf/download/frsrelease/392/5076/blackfin-jtag-tools-08r1.5-14.src.tar.bz2。将其中的jtag.tar.bz2、gdbproxy.tar.bz2和jtag.diff解压出来,例如储存为E:\Mum\urjtag_gdbproxy\jtag.tar.bz2、E:\Mum\urjtag_gdbproxy\gdbproxy.tar.bz2和E:\Mum\urjtag_gdbproxy\jtag.diff。然后:

$ cd /cygdrive/e/mum/urjtag_gdbproxy
$ tar xvjf jtag.tar.bz2
$ tar xvjf gdbproxy.tar.bz2
$ patch -p0 <jtag.diff

当然可以使用svn下载最新的代码:

$ cd /cygdrive/e/mum/urjtag_gdbproxy
$ svn checkout svn://sources.blackfin.uclinux.org/toolchain/trunk/jtag jtag
$ svn checkout svn://sources.blackfin.uclinux.org/toolchain/trunk/gdbproxy gdbproxy

假设MumJTAG的驱动程序存放E:\Mum\MumJTAGDriver,可以编译urjtag:

$ ./configure --prefix=/cygdrive/e/mum/newbuild/jtag/build --with-ftd2xx=/cygdrive/e/mum/mumjtagdriver
$ make
$ make install

我编译的时候有很多参数类型不匹配的警告,无视它们了……接下来编译gdbproxy,这个优点麻烦,首先确认在你的Cygwin里安装的GCC必须是4.X版本的,然后编辑E:\Mum\urjtag_gdbproxy\gdbproxy\configure.in,找到这段

if test "$host_os" = "cygwin" ; then
    CFLAGS="$CFLAGS -mno-cygwin"
    LIBS="$LIBS -lws2_32"
fi

改成这样

if test "$host_os" = "cygwin" ; then
#    CFLAGS="$CFLAGS -mno-cygwin"
    LIBS="$LIBS -lws2_32 -lintl -lioperm /cygdrive/e/Mum/MumJTAGDriver/i386/ftd2xx.lib"
fi

解释下,应该是gdbproxy的Makefile兼容性不够好,用Cygwin 3.X的GCC有很多错误。另外用4.X的GCC也必须加上intl、ioperm等库,我不太懂Makefile的编写,希望明白的大虾们予以指正。另外,必须加上FTD2XX库,这个库就在驱动程序的目录里,例如前文的E:\Mum\MumJTAGDriver\i386\ftd2xx.lib。然后就可以编译了:

$ cd /cygdrive/e/mum/urjtag_gdbproxy/gdbproxy
$ CC=gcc-4 ./configure --prefix=/cygdrive/e/mum/urjtag_gdbproxy/gdbproxy/build
$ make
$ make install

gdbproxy没有什么配置文件,但是需要在初始化的时候指定JTAG电缆的种类。使用的时候先将MumJTAG连上目标板并给目标板上电,然后:

$ cd /cygdrive/e/mum/urjtag_gdbproxy/gdbproxy/build/bin
$ ./gdbproxy bfin --connect="cable USB-to-JTAG-IF ftd2xx-mpsse 0725:6010"

Remote proxy for GDB, v0.7.2, Copyright (C) 1999 Quality Quorum Inc.
MSP430 adaption Copyright (C) 2002 Chris Liechti and Steve Underwood
Blackfin adaption Copyright (C) 2008 Analog Devices, Inc.

GDBproxy comes with ABSOLUTELY NO WARRANTY; for details
use `--warranty' option. This is Open Source software. You are
welcome to redistribute it under certain conditions. Use the
'--copying' option for details.

Initializing on FTDI device 0725:6010
IR length: 5
Chain length: 1
Device Id: 01000010011110100101000011001011 (0x00000000427A50CB)
  Manufacturer: Analog Devices
  Part(0):         BF533
  Stepping:     4
  Filename:     /cygdrive/e/mum/urjtag_gdbproxy/jtag/build/share/urjtag/analog/b
f533/bf533
warning:   bfin: no board selected, BF533 is detected
notice:    gdbproxy: waiting on TCP port 2000

这说明gdbproxy已经找到目标CPU了。gdbproxy也支持很多种FT2232电缆,MumJTAG兼容USB to JTAG Interface,所以写“USB-to-JTAG-IF”;我用的是FTD2XX的驱动,所以写“ftd2xx-mpsse”,“0725:6010”是VID和PID。具体的使用说明,请看blackfin.uclinux.org的wiki。

如果你觉得以上这一切都很麻烦,那么,你可以从EE小站的SkyDrive下载已经编译好的OpenOCD、urjtag和gdbproxy。注意,这些程序必须使用FTDI官方的FTD2XX驱动;这些程序只能在Windows下运行。我测了下,应该不需要Cygwin的Dll;如果不是这样,请留言,我会把Dll加上。地址如下:
OpenOCD:http://cid-4201fdc93932ddaf.skydrive.live.com/self.aspx/Mum%e8%ae%a1%e5%88%92/MumJTAG/OpenOCD.rar
urjtag_gdbproxy:http://cid-4201fdc93932ddaf.skydrive.live.com/self.aspx/Mum%e8%ae%a1%e5%88%92/MumJTAG/urjtag%7C_gdbproxy.rar

March 16

Mum计划之陈年往事

 
嘿嘿,先做个铺垫,我的Mum计划基于我的毕业设计中嵌入式视觉这一块。毕业已经有段时间了,我觉得可以贴出来了。视频里的履带机器人识别的目标是我手里拿着的一个红色发光二极管,摄像头安装在机器人中间的那个小突起里面。
 
    
 
解释下那个履带机器人为什么“抽”着动:
设计机构的时候,电机功率选小了,如果不增加电机电压,机器人动不起来;但是增加了电压,机器人运动速度太快,转向无法控制。所以只好让机器人动一下,歇一下,看上去比较别扭尴尬。但是视觉识别部分是没有问题的,可以准确地找到我手里的发光二极管。
今后的目标,就是把这个东东发扬光大。