Archive

Archive for the ‘学习笔记’ Category

windows下修改环境变量的方法

April 26th, 2010 will No comments

Windows环境变量是Windows系统定义的环境变量,可以在命令行下(运行中输入cmd回车),通过set命令查看,这些变量对于编写批处理文件用处很大,在批处理中%XXX%来使用一个环境变量即可,XXX代表你想使用的环境变量。环境变量中使用较多的是%path%,通常用来方便命令行处理,在运行中快速运行程序,用到了该环境变量。

通常可以通过cmd命令行下set xname=xxx来设置环境变量,如set %path%=%path%;c:,这是将c盘根目录增加至path环境变量。其它的修改方法类似。但这么改变是临时的,在下次本次关闭cmd之后,此环境变量将失效。如果需要永久设置一个环境变量可以通过“我的电脑右键属性->高级系统设置->高级->环境变量”来设置。由于Windows系统定义的环境变量很多,如果每次都这么设置在某些时候也是件很麻烦的事情。将已经修改后的环境变量导出备份,备份位置为[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session  Manager\Environment],下次需要修改直接双击导入就可以了。

Categories: 学习笔记 Tags:

TMS320VC33下crc16源程序

April 24th, 2010 will No comments

在对DSP编程,或者说是嵌入式编程之前必须对芯片有所了解,Datasheet和User‘s Guide必不可少。在编写CRC校验的时候遇到了TMS320VC33的字长问题,在解决了问题之后将多项式为X16+X12+X5+1的符合CCITT标准的CRC16源码发上来。目前VC33中运行正常的是查表法的程序。还有一个移位法的程序,对于非整字节校验也是有很有用的,但未经过验证,其实也很简单,就是运算效率较低,就不发了。

/*******************************
writer:will@xinzero.com
date:2010-4-9
*******************************/
static unsigned short CRC16Table[256] = {
 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
};

unsigned short getCRC16(unsigned long int *pMsg,unsigned int len)
{
 unsigned int i=0,j= 0;
 unsigned int CRCindex = 0;
 unsigned short CRC16Temp=0;
 CMD_WORD byte_word;

 for(i=0;i<len;i++)
 {
  byte_word.i = pMsg[i];

  CRCindex   = ((CRC16Temp>>8) ^ (byte_word.b.cmd0&0xff))&0xff;
  CRC16Temp<<= 8;
  CRC16Temp ^= CRC16Table[CRCindex];
  CRC16Temp &= 0xffff;

  CRCindex   = ((CRC16Temp>>8) ^ (byte_word.b.cmd1&0xff))&0xff;
  CRC16Temp<<= 8;
  CRC16Temp ^= CRC16Table[CRCindex];
  CRC16Temp &= 0xffff;

  CRCindex   = ((CRC16Temp>>8) ^ (byte_word.b.cmd2&0xff))&0xff;
  CRC16Temp<<= 8;
  CRC16Temp ^= CRC16Table[CRCindex];
  CRC16Temp &= 0xffff;

  CRCindex   = ((CRC16Temp>>8) ^ (byte_word.b.cmd3&0xff))&0xff;
  CRC16Temp<<= 8;
  CRC16Temp ^= CRC16Table[CRCindex];
  CRC16Temp &= 0xffff;
 }
 return CRC16Temp;
}
Categories: 学习笔记 Tags: ,

TMS320VC33字长问题

April 21st, 2010 will No comments

TMS320VC33是TI经典的浮点运算DSP,是从c3x中演变而来的,具有低功耗,大RAM(与c3x相比),在2000年的设计中使用较多,目前已经停产。就这么个片子把我搞惨了。

首先是原本的程序用C编程,使用File级的优化-03,优化级别最高了,对于代码的分析就有困难了,但原本的程序经过使用验证是没有问题的。现在的工作是需要加入一个CRC校验函数。首先通过VC2005编写一个可以在windows下正确运行的crc c程序,用cc编译后下载到片子上运行,从串口看数据crc校验错,程序有问题。开始怀疑编译器优化有问题,将此文件的优化去掉,还是不对。又怀疑是crc算法效率太低,采用bit移位法计算,改变crc算法,采用查表法,但是不对。

由于完整程序太大,不能在线仿真,所以调试起来很麻烦。最后没有办法,单单将crc函数挂上仿真器单独跑,结果crc错。这么就好找原因了,将每次crc查表的结果printf出来,很快就找到原因了。在程序中查表的位置号用unsigned char变量,crc结果用unsigned short,从中间结果看unsigned char型变量可以达到0×400值,unsigned short可以达到0×1287D0,这crc能校验对才有问题呢?printf sizeof 各种数据类型发现,在VC33中unsigned char、unsigned short、unsigned int、unsigned long int的长度都是1,位长度都是32bit,也就是说在VC33定义的变量类型只是个符号,与内存的分配无关,通常情况在cc下将float赋给int,连个warning都没有。在软件仿真和硬件仿真下都可以验证,这是编译器决定的。找到了原因,在每次运算完之后,根据理想的数据类型,取有效的位数即可(铵位与运算)。

另外VC33的地址空间也是与1字(int)对应的,就是一个地址对应一个存储空间,只是这个存储空间是32bit长。

最早使用ADI的BF系列芯片也没有这样的,到后期使用TI的C6000系列数据类型也是与存储空间严格对应的。

Categories: 学习笔记 Tags: ,

编程读取注册表获取串口信息(支持Vista)

March 10th, 2010 will No comments

在编写串口通信程序时,经常需要列举计算机上目前可用的串口。最简单的方法是通过CreateFile串口号1~256(XP系统系统下最大支持的串口号为256),查看返回值,如果返回非INVALID_HANDLE_VALUE就证明此串口号存在。此方法简单实用,因为在只有一个串口的情况也需要遍历256个串口,需CreateFile256次,效率较低,而且不能显示目前正在使用的串口号。

下面介绍通过读取注册表获取串口号与串口个数的方法。

#define MAXCOMNO 256  //最大COM号256
typedef struct{
 char name[8];
 short no;
}SCOM;

/////用读注册表的方式查看系统的串口设备
void GetAvailableCom(SCOM *port,int &cnt)
{
 HKEY  hKey; 
 LONG  ret; 
 OSVERSIONINFO    osvi; 
 BOOL  bOsVersionInfoEx; 
 CString  keyinfo;
 unsigned char comm_name[40];
 char ValueName[40];
 char szNO[3];
 int  i=0,j=0;
 cnt=0;
 DWORD  sType,Reserved,cbData,cbValueName;
 
 ZeroMemory(&osvi,  sizeof(OSVERSIONINFO)); 
 osvi.dwOSVersionInfoSize  =  sizeof(OSVERSIONINFO); 
 
 keyinfo.Format(_T("HARDWARE\\DEVICEMAP\\SERIALCOMM"));
 //CString  keyinfo=_T("HARDWARE\\DEVICEMAP\\SERIALCOMM");

 i=0;  sType=REG_SZ;Reserved=0; 
 bOsVersionInfoEx  = GetVersionEx(&osvi); 

 ret=RegOpenKeyEx(HKEY_LOCAL_MACHINE,keyinfo,0,KEY_ALL_ACCESS,&hKey); 
 if  (ret==ERROR_SUCCESS)
 {
  if  (osvi.dwPlatformId  ==  VER_PLATFORM_WIN32_WINDOWS)    //WIN32,not used
  { 
   for(i=1;i<=MAXCOMNO;i++) 
   {
    memset(comm_name, 0, 40);
    sprintf((char*)comm_name,"COM%d",i);
    ret=RegEnumValue(hKey, i, ValueName, &cbValueName, NULL, &sType, comm_name, &cbData);
    if(ret==ERROR_SUCCESS)
    {
     i++;
    }

   } 
  } 
  else  if  (osvi.dwPlatformId  ==  VER_PLATFORM_WIN32_NT) //WINNT XP 2000
  { 
   do   
   { 
    cbData=40;cbValueName=40; 
    memset(comm_name,0,40);   
    memset(ValueName,0,40);
    memset(szNO,     0, 3);
    ret=RegEnumValue(hKey, i, ValueName, &cbValueName, NULL, &sType, comm_name, &cbData); 
    if  (ret==ERROR_SUCCESS) 
    { 
     for(j=0;j<cbData;j++)
     {
      port->name[j]=comm_name[j];
      if(j>2 && j<6)
      {
       szNO[j-3] = comm_name[j];
      }
     }
     port->no = atoi(szNO);
     port++;
     cnt++;
     i++; 
    } 
   }while(ret==ERROR_SUCCESS); 
  } 
 }
 RegCloseKey(hKey);
}

port包含串口名称与编号,由于注册表中的串口名称排列并非安装串口号顺序排列而是随即排列的,便于界面中顺序列出串口号,故分别保存便于判断。cnt返回当前计算机中包含的串口数量。

注:由于在串口号大于8之后,不能直接用COM10来CreateFile,而要用\\\\.\\COM10的形式,而在COM8一下采用\\\\.\\COM1来CreateFile也是可以的。
在Vista下用此程序来读取串口号失败,其实并没有失败而是在Vista下访问注册表需要管理员权限。解决办法单击你的程序,右键属性,选择“兼容性”选项卡,勾选最下面的“请以管理员身份运行改程序”。

Categories: 学习笔记 Tags: , ,

FPGA中的多时钟设计

January 27th, 2010 will No comments

多种独立时钟在SoC(system-on-chip)设计中已普遍存在。很多SoC设备接有许多接口,这些接口根据标准运用了完全不同的时钟频率。

很多现代的串行接口继承了片上其它接口的异步性;而有些则直接从输入数据流中继承时钟。通过设计主要的SoCs子模块运行独立的时钟解决大片子中的时钟脉冲相位差,已经成为一种趋势。

由于这些原因,做SoC项目的设计人员一定会遇到多时钟和面对设计使用两个独立时钟芯片的逻辑连接问题。每个不同的时钟部分被认为是一个时钟域。在不同时钟上的逻辑接口被称作时钟域交叉或时钟域边界。对穿越时钟域边界的信号的处理是成功设计SoC的关键。

问题1:亚稳定性
设计人员必须考虑的第一个多时钟问题是信号从一个时钟域到另一个时钟域的亚稳定性问题。许多设计人员明白在实际电路中亚稳定性确实是个问题,现代RTL(寄存传输级)设计的抽象概念和静态的时序分析并不能完全屏蔽设计者对根本物理实现的担心。

无论何时一个信号进入一个时钟域的元件,如触发器,无论此时钟域与信号时钟多接近,都存在潜在的亚稳态问题。每当发生这样的情况,触发器立即产生不确定的值,在触发器的值被设置之前它的输出信号将不能使用。

在一个异步时钟边界,接收端时钟用来捕获发送端触发器的每一个信号。因为没有定义时钟与信号间的时间关系,所以它们完全可以同时传输。这样,在接收时钟域存在亚稳定性的问题。

这不是理论的、潜在的。在实际系统运行中,GHz时钟速率芯片的设计错误可以很快表现出亚稳态的效果。这些影响通常包括在时钟域之间丧失关键握手信号,以及失效多比特数据的严重问题,很有可能需要芯片的重新设计。

很多设计师也知道,教科书中通过在每路穿越时钟域边界的信号上使用两级触发器解决亚稳定性问题。即使第一级触发器没有成为亚稳态,也有极高的可能性使信号通过第二级的时间将被确定。这种两级触发器结构被称为同步器,和设计师通常讲的穿越时钟域同步信号。

问题2:复位同步
复位信号不同步是多时钟设计的一个相关问题。设计师有时会忘记,复位信号为受到亚稳定影响,应该加同步器加以保护。一般来说,整个系统可以使用单一信号复位,因此,必须传到所有时钟域的所有时钟元件。

复位信号的有效沿没有必要同步,因为所有的状态元件复位定义为初始值,并且复位信号会保持足够的时钟周期,取出所有的亚稳定状态。

但是,复位停止必须保持同步,这样触发器在复位状态恢复后不会处于亚稳态。在设计中,通过给进入每一个时钟域的复位信号一个独立的同步器来实现。

问题3:毛刺消除跨时钟域
尽管出于实际的目的同步消除了亚稳态,但是它不足以解决其它类型的多时钟设计错误。在多时钟设计中第三类常见错误是允许毛刺从驱动时钟域传播到接收时钟域。

因为一个接收时钟域的触发器可以及时的从驱动时钟域的任意点采样信号,甚至是很窄的毛刺也可能被捕获,并视为一个有效值。由于时钟关系的变化特性,这种毛刺电压不能通过静态时序分析检测。

避免种类问题最常见的方式是,使从驱动时钟域触发器输出的信号直接进入同步器。这有效地定义了一个三个阶段同步器,第一个触发器由驱动时钟驱动,剩余的两级由接收时钟驱动。尽管设计及时钟结构的自动分析更加可靠,但这种方法可以作为设计审查。

问题4:接收时钟域不恰当的保持时间(hold times)
在多时钟设计中第四类问题是,不稳定数据从一个时钟域到另一个没有遵守保持时间。信号从一个快速时钟域到一个慢速时钟域时,在驱动时钟域必须稳定几个时钟周期,保证接收域中的慢速时钟不会完全丢失转换。

如果这个转换丢失,数据将丢失。例如一个信号从33MHz的PCI域到12MHz的USB域,必须保持稳定3个时钟周期,才能保证被接收。

当数据信号在逻辑控制信号的保护下,跨越时钟边界,保持时间(hold times)也是非常重要的。

问题5:跨越式中边界丢失信号间的相关性
在多时钟设计中的最后一类问题是,相关信号在跨越时钟边界后失去相关。这个问题是最不直观的。这将导致非常不确定的行为,如数据丢失,算术结果破坏。

这类不直观的问题在可视化的检查中很难被发现,特别是用RTL电路形式,在设计审查是经常被忽视。必须将严格的设计规则和有效的自动分析用于这类问题。

在广泛的相关信号中,可能产生相关性丢失的几种不同方式,包括:

  • 总线的多数据位
  • 单信号的多次复制
  • 握手信号,如请求与应答信号
  • 明显不相关的信号合并在接收时钟域的同一逻辑中

无论何时一个信号进入亚稳态,可以使用同步器确定它的值,但是在接收时钟域不能保证在信号有效之前的精确周期数。因此,任何一个多位信号,每位有独立的时钟同步,每位在到达接收时钟域时,相对其它位将产生倾斜。

即使亚稳定不发生,任何成对数据位信号在到达相应的同步器之前,通过不同的线路或者电特性使两个信号产生不同的延时,都可能丢失同步。

可能一个同步器采样输入信号,并且在另一个同步器捕获信号变化之前,先捕获信号的变化,这样,两个信号将在一个时钟周期内倾斜,并且不再相关。

两个明显独立的信号来两个分离的时钟域,最终反馈进相同的接收时钟域,这是可能产生丢失相关性。这一模式被称作再收敛。在设计复查中,通过同步原理的手动检查方式很发现。

解决方法:时钟验证(Clock intent verification)

尽管多时钟设计的挑战的确让人沮丧,但是幸运的是以上所有描述的问题,是可以自动分析的。然而不是所有的问题都是完全一致的。可能为了避免可疑逻辑的细节警告,设计人员可以检查逻辑是否正确。时钟验证(CIV)是分析时钟结构,报告错误与警告的一个过程,然后使用详细正式的报告验证这些不能被证明问题。

任何CIV必须解决多时钟设计中五个问题的一个。这一进程始于RTL的结构分析,追查设计中从触发器到其它级元器件的时钟与复位。这一过程可以自动设别:

  • 设计中的所有异步时钟域
  • 穿越时钟域的所有控制和数据信号
  • 任何丢失同步或者不正确同步的跨时钟域信号
  • 任何在输入端有潜在毛刺的同步器
  • 任何信号有扇出倍同步器
  • 任何在接收时钟域再收敛的独立同步信号
  • 任何复位信号没有合理同步的时钟域
  • 任何存在潜在毛刺的门时钟或派生时钟

如果合理实现,这些结构的分析可以很快的在SoC上实现,最少的设计输入要求,尽管在对输入信号做简单的描述,对分析是有好处的。

根据这些信息,分析可以极端正确,以至于虚假的错误和警告将不会报告。设计者将只会看到真正的问题,或者是有关设计的有用反馈信息(例如一系列合理同步的信号)。

尽管很多类型的多时钟设计问题可以通过CIV的结构分析来检测,但还是有部分不能。对于变化的多时钟域信号处理与跨时钟域数据的稳定性验证,需要彻底地分析与正式的验证。

既然正式的验证需要对设计断定,一个CIV解决方案必须能够产生三种类型的断定,来表现信号穿过多时钟域的期望行为:

  • 断定多位数据跨域时钟域时,必须是灰数据(每次仅有一位数据改变);这是为了避免丢失相关性
  • 断定具有同步器的信号能够保持稳定,持续足够长的时钟周期,以便接收时钟域能够检测,这是为了避免丢失数据
  • 断定没有同步器的信号(比如数据总线),在接收时钟域采样时间内,能够保持稳定,这也是为了避免数据丢失

正式的验证试图证明这些断定在任何假定下都不能违反,或者试图通过举反例来证明断言不能违反。

无论何时一个证据被发现,设计者将信心大增,因为他们知道没有可能特定时钟跨越错误将会发生。无论何时一个范例被发现,正式验证已经发现了一个实际的bug,如果不解决,将导致芯片不能工作。正式的工具必须能够提供足够的信息让设计者解决问题,然后重新运行观察是否能够找到证据,去除心中久留的顾虑。

尽管正式验证是一个彻底的技术,但是在复杂的SoC设计中,并不是所有的断定都能够被证明的。出于这个原因,如果CIV方法能够产生符合仿真形式的断定,将是有价值的。如果无法找到证据,但是断定在整个成百万甚至上十亿个时钟周期内运行都不产生冲突,那么,设计师仍然可以获得一项多时钟设计正确性推断的重要措施。

Categories: 学习笔记 Tags: