Aguilera

  • 2019-01-15
  • 发表了主题帖: DSP的PCIJMC2000计算机数据加密卡设计

          计算机数据加密卡PCIJMC2000采用DSP与FPGA实现数据加、解密。PCIJMC2000能提供达40Mbit/s的数据处理速度,采用硬件和软件相结合的加密方法,可方便升级算法,并使加密程序代码更加安全可靠。DSP具有高度的并行结构、专用硬件逻辑以及许多专用指令,可以实现快速加密算法,DSP的双访问RAM和主机并行接口可以实现数据PCI传送和DSP处理同时进行,采用深度缓冲技术使花在主机中断上的时间几乎可以忽略不计。       随着现代通信技术的发展,企业及个人越来越多地依赖于互联网进行信息交互。互联网是一个开放式系统,数据一旦上了互联网很容易受到各种有意或无意的入侵,这无论是对于越来越重视个人隐私保护的个人,还是对于越来越重视知识产权保护的公司企业都是无法容忍的,这就需要保密通信 。另外,保存在计算机中的数据也容易受到非法窃取,这就需要对长期保存的重要文件数据进行加密。因此,加密技术受到了越来越多的关注。       密码技术主要包括两部分:即基于数学的密码理论和技术(包括公钥密码、分组密码、密钥管理等)和非数学的密码理论和技术。目前厂商所采用的加密方法可主要分为两大类:软加密和硬加密。软加密即是用纯软件方法来实现数据加密,主要有密码方式、软件自校验方式、许可证管理方式、钥匙盘方式等。所谓硬加密就是通过硬件和软件结合的方式来实现对数据的加密。特别是采用了独特的噪声技术后,可以在发送端发出的网络数据里加入由物理硬件产生的噪声,接收端依据通信协议自动滤除噪声,或者由物理噪声硬件产生随机密钥。       加密卡是结合软件加密与硬件加密的特点与优势,能用来在互联网上实现保密通信,或对计算机文件数据加解密。目前国内加密卡的原理是将加密算法固化在加密卡上的FPGA中,而由主机承担加密运算工作如非平衡算法等。 这样做有几个不足: 1、主机因为运行复杂的加密算法程序而使主机系统性能下降; 2、加密算法程序在主机上运行使加密程序代码的保密性下降,易被破解; 3、主机每次处理的数据仅为32~128bit,造成中断频繁,大量时间花在了中断处理上,所以整个加密密过程速度仅达10Mbit/s[1]。为了改进这些不足,我们进行了加密卡的DSP实现研究,并成功开发了新一代加密卡——基于DSP的PCIJMC2000。 1  方案设计       DSP(Digital Signal Processor)是数字信号处理专用芯片,具有高度的并行结构,专用硬件逻辑以及许多专用指令,可以实现快速加密算法,DSP的片上双访问RAM(DARAM)和主机并行接口(HPI)可以实现数据PCI传送和DSP处理同时进行。PCIJMC2000方案设计如图1所示。       DSP的片上DARAM可以在一个机器周期内被访问两次(两次读操作,或一次读一次写操作),作为DSP的数据空间用作接收和发送缓冲区,片外RAM作为DSP的程序空间用于暂存运行的DSP加密程序代码。        由于采用了两对缓冲区,主机对缓冲区的读写和DSP对缓冲区数据的处理可以同时进行,理论上加密速度可以达到主机读写缓冲区速度(HPI传送速度)的一半和DSP处理速度(含DSP读写操作)二者中较慢的一个。DSP的主频为100MHZ,HPI的时钟为DSP主频的1/5,所以HPI的传送速度为 100M×8/5=160 Mbit/s,加密卡的最高处理速度为HPI传送速度的一半即80M bit/s。当DSP的片外RAM延时不大于7ns,且平均每个字的处理时间不超过20个DSP时钟周期时,则DSP的处理速度不低于HPI的传送速度的二分之一,因此加密卡可望获得接近于40Mbit/s的处理速度。      在这种方案中,加密算法(分组密码算法)固化在卡上的FPGA中,DSP运行软件加密算法(非平衡算法等),主机的工作仅仅是读写操作,不再参与复杂的加密运算,因此由加密卡与主机组成的整个加密系统能获得真正意义上的高速处理。   图1 PCIJMC2000设计方案 2  方案实现 实现该方案的原理框图如图2所示: 图2 PCIJMC2000原理框图       PCIJMC2000分为四个模块:PCI接口、DSP、加密硬件和CPLD。加密算法芯片承担硬件加密工作,加密算法程序代码放在访问延时较长的FPASH中,启动时由bootloader搬到访问延时很短的RAM上运行以实现软件加密,通过向FLASH灌入不同的加密算法程序,就可以实现不同的加密算法。物理噪声芯片提供密钥所需的噪声,CPLD实现组合逻辑电路和时序逻辑电路功能,担当控制器的角色。 芯片选择: DSP:TI公司的TMS320VC5409,工作频率100MHz; PCI接口:TI公司的PCI2040,工作频率33MHz[4]; CPLD:Xilinx公司的XC9572XL,延时7ns; RAM:Cypress公司的CY7C1021V33,延时7ns; 加密算法芯片:SSF10B,反熔丝FPGA实现的SSF10密码算法芯片,分组模式为64位,支持分组密码算法的ECB、CBC、CBF和OFB工作模式。 DSP电源采用TI公司的DSP专用电源芯片TPS73HD318,输入5V,输出1.8V和3.3V。 由于现在PC机的PCI插以5V为主,所以我们设计的PCIJMC2000采用5V信号环境。PCI插槽提供3.3V和5V电源。电路中需要用到的电源有三个:   1.8V作DSP的核电压CVDD; 3.3V和5V作为电路中各芯片的工作电压。       为了合理分配电源,我们将PCI插槽提供的5V和3.3V电源全部加以利用,5V和3.3V直接提供给PCIJMC2000上各芯片使用,另外将5V电源送到DSP的电源芯片TPS73HD318上,其输出的1.8V电源供给DSP作核电压。PCI2040及DSP的所有未用的输入端都必须用上拉电阻接到有效逻辑电平上,以保证这些输入端处于稳定的高电平而不会因悬空而发生电平漂移。 3  系统调试        由于利用DSP实现加密卡是我们提出的新方法,现在还在开发阶段,我们只能进行硬件测试。硬件测试工作主要有两部分,一部分是DSP模块,另一部分是PCI驱动测试。 3.1  DSP模块调试 为了测试PCIJMC2000上的DSP模块,我们首先编写了一个DSP程序并在软件仿真器CCS1.2上调试通过。 给存储器分配置的地址如下[3][4]: 数据空间: 片上DARAM 0000H~7FFFH,片外FLASH 8000H~FFFFH; 程序空间:片外RAM0000H~7FFFH; 该测试程序只是执行读写操作,通过CCS的调试窗口观察被写的存储器单元的内容有无变化即可知道硬件电路是否完好。 测试程序经CCS在DSK板子上调试通过后,我们再将硬仿真器接到PCIJMC2000的JTAG接口上。硬仿真器能够正确识别PCIJMC2000上的DSP,运行测试程序,采用单步运行模式,CCS能够向PCIJMC2000的DSP或片外存储器写入数据或读取数据。 通过PCIJMC2000上的手动复位按钮能够复位DSP。 3.2  PCI驱动测试       为了测试DSP与主机之间的硬件电路,我们利用DriverWorks的向导程序Driver Wizard,编写了一个简单的Win98 PCI驱动程序。PCI2040提供两个地址空间资源:一个4K空间用于映射HPI的控制和状态寄存器组,一个32K空间用于映射DSP的片上存储器,这两个地址空间均可以映射到主机存储器空间或IO空间,我们将其全部映射到主机存储器空间。       在框架程序的PcitodspDevice.cpp文件中,查找有“TODO”提示的地方,这是程序员需要添加具体功能代码的位置。程序主要实现ReadFile()、WriteFile()这两个重要的IRP调用。我们编写的只是一个测试程序,目的是为了检测硬件电路是否完好,只有一些读写操作,读写操作的位置为32K空间中前8K空间的一个字。由于DSP片上存储器的前128个字为寄存器和Scratch-Pad RAM,所以读写操作应从128以后开始,我们选取0x200单元。 修改并设置好程序中的参数后,编译生成了.sys和inf文件。再对.inf文件进行修改,添加设备信息,如:设备名称”数据加密卡”,驱动程序编译完成。 由于windows98和windows2000支持即插即用,可以先关机,插入PCIJMC2002卡,然后开机。当计算机启动时,它会自动查找到PCI卡并提示装入驱动程序,指定.sys和.inf文件的位置后,驱动程序会自动装入,安装完成。 安装完成后,从加密卡的设备信息框中看到如下一些信息: 设备名称:数据加密卡          中断请求:09 内存空间0:df009000-df009fff         内存空间1:df000000-df007fff 设备名称是在.inf文件中手动加入的信息,中断请求和内存空间是计算机自动分配的。 主机将DSP的片上存储器映射到0xdf000000开始的连续的32K内存中(实际只能用前面8K,后面24K未用),将PCI2040的控制与状态寄存器组空间映射到0xdf009000开始的连续的4K内存中。 我们第一次读入DSP的0x200单元的内容为0。向该单元写入后,再读取该单元的内容变成了0xa0a0(在WriteFile()函数中输出的值)。 PCIJMC2000硬件系统调试全部通过。 4  结论    本文创新点:1、利用DSP的片上存储器设计了深度缓冲结构,实现了数据传输和处理并行进行,提高了加密流程处理速度;2、设计了加密算法代码运算与主机的脱离,不仅使主机仅承担数据传输任务,而且使加密软件代码对主机隐蔽,屏蔽了用户,有效防止了对加密算法代码的恶意窃取,使得加密程序代码保密性很高。3、通过对加密卡上FLASH芯片的写入可方便实现在线升级。

  • 2019-01-11
  • 发表了主题帖: 让嵌入式设备枚举成WinUSB设备

           USB接口作为PC上最流行和通用的接口,具备可连接多种类型的设备,连接简单,即插即用,支持热插拨,多数应用场景下不需要提供独立的电源,高传输速率,高可靠性等特点,被越来越多的产品作为首选接口作为接入PC的连接方式。为了简化USB设备的开发和接入到PC系统,微软开发了WinUSB,可以将Winusb.sys作为设备功能驱动程序安装,并提供WinUSB API供应用程序访问设备。         一直以来,除了USB HID设备,其他类型的设备在WINDOWS环境下需要安装驱动程序才能工作。要实现USB设备免驱,就只能使用HID设备。而HID设备传输速度慢,在有些场合必须使用Bulk类型进行批量传输时,就必须使用第三方驱动或者自己开发一个驱动,使得项目开发非常麻烦。         现在好了,自从微软推出了WinUSB,在微软的最新操作系统上实现简单的Bulk类型批量传输也变得非常的方便快捷,在研发过程当中或者一些对于差异化要求不高的场合,是非常适用且容易实现的。本文致力于实现一个最简单的WinUSB通信系统,以满足此类需求。        系统通过USB描述符来确定以何种USB Class类型来工作。如果希望WINDOWS能够将嵌入式设备识别为WinUSB设备,则其描述符至少应当包含以下字段: 1、支持 OS 字符串描述符: 为了让 USB 驱动程序堆栈了解设备支持扩展的特征描述符,设备必须定义存储在字符串索引 0xEE 处的 OS 字符串描述符。在枚举过程中,驱动程序堆栈查询字符串描述符。如果存在描述符,驱动程序堆栈会假定设备包含一个或多个 OS 特征描述符和检索这些特征描述符所需要的数据。检索的字符串描述符具有 bMS_VendorCode 字段值。该值为1表示USB驱动程序堆栈必须用来检索扩展特征描述符的供应商代码。 #define bMS_VendorCode              ( 0x01 ) // "MSFT100" : index : 0xEE : langId : 0x0000 const U8 OS_StringDescritpor[ ] = { 0x12,  0x03,  'M',  0,  'S',  0,  'F',  0,  'T',  0,  '1',  0,  '0',  0,  '0',  0,  bMS_VendorCode,  0 }; 2、设置兼容ID特征描述符: const U8 WINUSB_ExtendedCompatId_Descritpor[ ] = { 0x28, 0x00, 0x00, 0x00,           // dwLength 0x00, 0x01,                             // bcdVersion 0x04, 0x00,                             // wIndex 0x01,                                       // bCount 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,       // Reserved[7] 0x00,                   // bFirstInterfaceNumber 0x01,                  // RESERVED ( 0x01 ) 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,       // compactiableID[8] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Reserved[6] }; 注:WinUSB还支持复合设备,对于单一传输类型最简系统,我们忽略复合设备的要求即可。compatibleID字段必须指定 "WINUSB" 作为字段值。其他可以根据需求更改。 3、注册设备接口 GUID描述符: 该描述符用于区分不同的WinUSB设备。 const U8 WINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] = { 0x8E, 0x00, 0x00, 0x00,  // dwTotalSize = Header + All sections 0x00, 0x01,                 // bcdVersion 0x05, 0x00,                 // wIndex 0x01, 0x00,                 // wCount 0x84, 0x00, 0x00, 0x00,     // dwSize -- this section 0x01, 0x00, 0x00, 0x00,     // dwPropertyDataType 0x28, 0x00,               // wPropertyNameLength  'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0x00,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0, 'G',0,'U',0,'I',0,'D',0,0,0, 0x4E, 0x00, 0x00, 0x00,     // dwPropertyDataLength : 78 Bytes = 0x0000004E '{',0,'1',0,'2',0,'3',0,'4',0, '5',0,'6',0,'7',0,'8',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'3',0,'4',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0,'A',0,'B',0,'C',0,'}',0,0,0 };// bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}" 4、端点描述符: 按实际的需求的配置端点数量和类型,即可完成嵌入式设备的描述符配置了。 一般固件程序可以通过MCU厂家提供的范例程序进行修改,这里省略USB固件功能的说明。只要包含以上三个描述符中的必须的字段,就可以成功枚举成USB Device。枚举成功后在设备WINDOWS设备管理器中可看到类似设备,如下图1所示。 图1 成功枚举为USB Device       PC机软件相对来说比较简单,并且微软官方也给出了示例代码。唯一需要注意的是,对应的软件程序获取WinUSB设备句柄的GUID参数,需要与嵌入式设备的描述符中的GUID保持一致。GUID是WinUSB用以区分设备的唯一标志。GUID,是Globally Unique Identifier的简称,翻译为全局唯一标识符,是一种由算法生成的二进制数据,长度为128位的数字标识符。 具体实现步骤如下: 1、创建设备的文件句柄: 调用SetupDiGetClassDevs 获取设备信息集的句柄; 调用 SetupDiEnumDeviceInterfaces 枚举设备信息集中的设备接口并获取有关设备接口的信息; 调用 SetupDiGetDeviceInterfaceDetail 获取设备接口的详细信息,所获取的信息通过SP_DEVICE_INTERFACE_DETAIL_DATA结构返回。由于该结构大小无法提前获取,故需连续两次调用该函数,第二次调用时接口详细信息将填充到根据第一次调用返回值所确定大小的该缓冲区,通过缓冲内该结构的DevicePath成员中可获得“设备路径”。 2、获取设备的 WinUSB 接口句柄: 调用 WinUsb_Initialize通过传递在创建设备的文件句柄中创建的文件句柄。 3、查询设备以获取 USB 描述符: 接下来,查询设备以获取特定于 USB 的信息,如设备速度、接口描述符、相关端点及其管道。调用 WinUsb_QueryDeviceInformation 从设备的设备描述符请求信息。调用 WinUsb_QueryInterfaceSettings 并传递设备的接口句柄,以获得对应的接口描述符。调用 WinUsb_QueryPipe 获取有关每个接口、每个端点的信息。此步骤不是必须的,因为端点方向及传输特性由嵌入式设备描述符决定,是已知的。 4、向默认端点发送控制传输: 此步骤也不是必须的。一般都不通过默认端点发送有效载荷。 5、发送 I/O 请求: 将数据发送到设备的批量输入和批量输出端点,这些端点即可分别用于读取请求和写入请求。调用 WinUsb_ReadPipe 从设备的批量输入端点读取数据。调用 WinUsb_WritePipe 通过批量输出端点将数据写入设备。在嵌入式设备的输出端点内写入数据之后,就可以在PC端读出数据。反之,如果在PC端对嵌入式设备的输入端点写入数据,则嵌入式设备会产生一个USB端点写入事件,具体如何捕捉该事件,则由MCU厂家的产品硬件决定,产生相应的中断信息,供中断服务程序来判断。一般而言,芯片厂家会提供MCU的USB通信基础范例程序,在其基础上做简单的修改和适配即可。 6、释放设备句柄 在完成对设备的所有必要的调用之后,释放设备的文件句柄和 WinUSB 接口句柄。CloseHandle 释放由 CreateFile 创建的句柄。 WinUsb_Free 释放由 WinUsb_Initialize 返回的设备的 WinUSB 接口句柄。 至此,已经完成了嵌入式设备端固件的USB代码移植和PC端应用程序的编写,就可以实现USB免驱设备的通信方式了。

  • 发表了主题帖: 基于单片机EEPROM解析

          在实际的应用中,保存在单片机 RAM 中的数据,掉电后就丢失了,保存在单片机的FLASH 中的数据,又不能随意改变,也就是不能用它来记录变化的数值。但是在某些场合,我们又确实需要记录下某些数据,而它们还时常需要改变或更新,掉电之后数据还不能丢失,比如我们的家用电表度数,电视机里边的频道记忆,一般都是使用 EEPROM 来保存数据,特点就是掉电后不丢失。我们板子上使用的这个器件是 24C02,是一个容量大小是 2Kbits,也就是 256 个字节的 EEPROM。        一般情况下,EEPROM 拥有 30 万到 100 万次的寿命,也就是它可以反复写入 30-100 万次,而读取次数是无限的。         24C02 是一个基于 I2C 通信协议的器件,因此从现在开始,我们的 I2C 和我们的 EEPROM就要合体了。但是大家要分清楚,I2C 是一个通信协议,它拥有严密的通信时序逻辑要求,而 EEPROM 是一个器件,只是这个器件采样了 I2C 协议的接口与单片机相连而已,二者并没有必然的联系,EEPROM 可以用其它接口,I2C 也可以用在其它很多器件上。

  • 发表了主题帖: 采用数字频率合成技术、FPGA和单片机进行扫频仪的设计

          一个网络的频率特性包括幅频特性和相频特性,在系统设计时,各个网络的频率特性对该系统的稳定性、工作频带、传输特性等都具有重要影响。实际操作中,扫频仪大大简化了测量操作,提高了工作效率,达到了测量过程快速、直观、准确、方便的目的,在生产、科研、教学上得到广泛运用。本设计采用数字频率合成技术产生扫频信号,以单片机和FPGA为控制核心,通过A/D和D/A转换器等接口电路,实现扫频信号频率的步进调整、数字显示及被测网络幅频特性与相频特性参数的显示。 1 系统总体方案及设计框图 1.1 系统总体方案          将输出频率步进可调的正弦扫频信号源作为被测网络的激励Vi,可得被测网络的响应为V0。通过测量各频率点的幅度就可得到V0和Vi的有效值,两者之比就是该点的幅度频率响应;对V0和Vi进行过零比较、整形,再送到FPGA测量相位差,即可得到相频特性。 输入g*(n)的输出v*(n)是v(n)的复共轭。于是得到输出y(n)的表达式: 采用数字频率合成技术、FPGA和单片机进行扫频仪的设计           因此,输出信号和输入信号是频率相同的正弦波,仅有2点不同:1 振幅被加权,即网络系统在ω=ω0的幅度函数值;2 输出信号的相位相当于输入有一个q(ω0)时延,即网络系统在ω=ω0的相位值。该方案幅度和相位测量的控制都通过FPGA实现,能够使测量结果精确。 1.2 系统总体设计框图 系统通过键盘扫描得到外界设置的扫频范围和频率步进,通过调用DDS控模块控制DAC904,输出扫频信号。由于信号在被测网络阻带内会有很大的衰减,故用程控放大处理经被测网络的扫频信号之后,利用AD637进行有效值采样,LM311进行整形。信号有效值经MAXl270进行AD转换后得到有效值的数字量,整形后的信号经测相模块处理得到相位差值。在FPGA中写入2个RAM存放被测信号的有效值和相位差值。完成一次扫频后通过波形显示模块将幅频、相频曲线显示在示波器上,并将特定频率点的幅度和相位差值在液晶显示器上进行显示。系统实现框图如图1所示。 采用数字频率合成技术、FPGA和单片机进行扫频仪的设计 2 系统功能部分设计 2.1 扫频信号的产生 直接数字合成(DDFS)信号源。它是一种完全数字化的方法:先将一个周期的正弦波(或者其他波形)的离散样点幅值的数字量预先存储于ROM或者RAM中,按一定的地址增量间隔读出,经D/A转换后成为不同频率的模拟正弦波信号波形,再经低通滤掉毛刺即可得到所需频率的输入信号。按此原理,DDS可以合成任意波形,且可以精确控制相位,频率也非常稳定。利用FPGA制作起来相当容易,且扫频步进实现简单。设FPGA内部的参考频率源的频率为fclk,采用计数容量为2N的相位累加器(N为相位累加器的位数),频率控制字为M,则DDS系统输出信号的频率fout=fclk/2N×M。频率分辨率为:△f=fclk/2N。 若选取晶振频率为40 MHz,频率控制字为24位,相位累加器的位数为31位,则输出频率范围为0.02 Hz~312 kHz,步进频率为40 MHz/231≈0.02 Hz。 系统采用高速14-bit电流输出型D/A转换器DAC904制作DDS扫频信号源。通过FPGA给其20 MHz的时钟信号以输出10 Hz~100 kHz的扫频信号。该器件制作成的PCB板中,很好地考虑了接地,使得输出信号在频率为1 MHz可以达到无明显失真。DAC904采用内部基准和双极性接法,输出信号幅值范围为0~5 V。其原理图如图2所示。 2.2 幅频特性测试方案 使用集成真有效值转换器AD637先检测出信号每个频率点的有效值,再经过A/D采样将得到的数据读到单片机中进行处理即可。该器件外接电路简单,工作频带很宽,与A/D转换器级联,可以对任何复杂波形的有效值、平均值、均方值、绝对值进行采样,测量误差小于±(0.2%读数+0.5 mV),可以达到很高的测量精度 2.3 相频特性测试方案        采用计数法实现相位的测量。计数法的思想是将相位量转化为数字脉冲量,然后对数字脉冲进行测量而得到相位差。对转换后的数字脉冲量进行异或运算,产生脉宽为T0、周期为T的另一路方波,若高频计数时钟脉冲周期为TCP,则在一个周期T的时间内的计数数值为: 式中,φx为相位差的度数。这种方法应用比较广泛,精度较高,电路形式简单,适合FPGA实现。 实际测量中,当两输入信号频率较高且相位差很小时,得到的脉冲很窄,这会造成较大误差。为了克服上述缺陷,引入等精度测量的思想(如图3),采用多周期同步计数法,利用触发器产生一个宽度为被测信号fa整数倍的闸门信号。利用计数器1测量出闸门信号内通过高频脉冲fm的个数N1,利用计数器2测量出相同时间内闸门信号、异或信号、高频脉冲三者相与后的脉冲数N2。因此,相位差值为△φ=N2/N1x360°。测量相位的同时,在FPGA内部引入一D触发器,用一路方波信号控制另一路方波,通过触发器输出的高低以判断信号相位差范围是大于180°还是小于180°。 2.4 系统显示电路设计       为了在示波器上显示曲线,需要通过2个D/A转换器向X、Y轴同步送入扫描信号和数据信号。X轴方向的DA转换器输出扫描信号为O~5 V的锯齿波信号,而数据信号为-5~5 V,反应了各个频率点上的信号幅值和相位,由另一片D/A转换器向Y轴方向输出。 3 系统软件设计       系统软件设计由单片机和FPGA组成。整个系统以用户按键中断为主线,调用不同的处理函数,与FPGA中各个控制模块之间,以总线的进行数据的交换,实现了系统测量频率特性的功能。软件流程图见图4。 4 结束语      本扫频仪利用数字频率合成技术(DDS)产生扫频信号,通过14位D/A转换器DAC904产生了10 Hz~100 kHz的正弦扫频信号,作用于被测网络。网络的输出信号通过有效值采样电路,以及由比较器LM311配合FPGA内部实现的测相电路,完成了对被测网络频率特性的测量。      为对系统的性能进行测试,制作了一个中心频率为5 kHz。带宽为±50 Hz的阻容双T网络。测试结果表明,在网络的通带和阻带内,相频特性测量均达到了3°以内的测量精度,幅频特性的测量误差均小于50%。此外,该系统可以通过键盘输入扫频范围,通过示波器显示幅频、相频曲线,并可以在液晶显示器上显示该网络在特定频率点上的幅度、相位特性值。该系统操作简单,成本低廉,测量精确,具有很强的实用性。

  • 发表了主题帖: 单片机有源蜂鸣器驱动之效率编程

    在项目中原理图如下: 如果不能保证I/O的输出性能可以根据情况增加上拉或者下拉电阻。 切入正题:在程序里面这个蜂鸣器的驱动就是个高低电平驱动。高电平三极管导通、蜂鸣器发声,低电平三极管关断、蜂鸣器不发声。这的确很简单,程序上最开始我是这样写的: 当然,如果单片机没有很好的I/O跳变函数也可以这样修改: 这里稍作解释: 1) 函数功能:蜂鸣器发声驱动 传入参数:蜂鸣器发声的次数 2) 传入的次数cnt需要再函数内翻倍。这是因为传入的参数是想让蜂鸣器连续的发cnt声。但是蜂鸣器除了发声还有不发声的时候。也就是说蜂鸣器每响一次都需要关闭一次,如果没有关闭操作肯定就不会出现响几声而是连续的响一声,这个也很容易推理。 3) 在while循环完之后需要加一个蜂鸣器关闭操作。 这里假如传进的参数是2,目的是让蜂鸣器响两声。根据程序的执行步骤: cnt2变成4。 第1次while(4) 蜂鸣器开 cnt自减到3 第2次while(3) 蜂鸣器关 cnt自减到2 第3次while(2) 蜂鸣器开 cnt自减到1 第4次while(1) 蜂鸣器关 cnt自减到0 第5次while(0) 跳出while 可以看出其实在while之后蜂鸣器状态已经是关闭的了,但是保险起见,确保函数调用完之后蜂鸣器是关闭的状态。比如第一个函数I/O跳变的就更需要保障了,因为代码上只能看出跳变,看不到跳变之后的状态。 至此,一个简单的蜂鸣器电路和驱动程序就都温习完了,接下来上干货: 在写程序的时候很多时候讲究程序的效率,比如这个蜂鸣器驱动,驱动过程中会降低效率,厉害的人很快能看出来,就是这个Delay延时的问题。但是上面也说了,不延时也是不行的。所以趋于效率我尝试着换了一种方法驱动蜂鸣器。 代码如下: 实现起来也很简单,简单说下原理: 1)首先是提供蜂鸣器驱动的I/O配置, 2)其次是定时器的配置 3)最后是定时器中断函数实现 我选用的定时器是项目单片机中最简单的一个定时器,配制成1ms中断,能够提供溢出中断。其实这个定时器我常用做计系统运行时间Systick_ms。但是该项目对这个系统时间没有用到,那就用这个定时器做文章把。 实现方法: 1、同样函数在调用蜂鸣器驱动的时候接口是一样的,传入的参数还是蜂鸣器的响声次数。 2、函数体变了,这里改成了两个变量的赋值,第一个BELL_CNT同普通方法中的cnt2,这里不再赘述。第二个是FLAG_BELL是用来保存蜂鸣器是否需要驱动的状态变量。所以既然是调用驱动函数,那肯定这个变量要为真。 3、定时器中断函数里面加上了一个静态变量NOW,他的作用就是和Systic_ms产生一个50ms的时间片,干嘛用?肯定是给蜂鸣器开关之间的延时用咯。模拟软件延时嘛。然后再来分析下这段代码: 1)首先这个NOW和Systic_ms是无条件需要赋值保证50ms时间片的。对应的代码为NOW=Systick_ms+50; 2)判断蜂鸣器驱动状态变量是不是真,如果不为真就关闭蜂鸣器,这个也是无条件的。 3)如果状态变量为真:蜂鸣器先跳变Bell_Tog();当然如果没有这个跳变函数也可以用上述的判断cnt的方法,就不多写了都是一样的。同时次数自减BELL_CNT--;同时判断是不是减到0了,减到0了说明响完了啊,那就把状态变量赋值为假。再次进来不管蜂鸣器是开着的还是关着的都会执行关闭操作,这个跟上面说的保险一样。 4)最后,这两个变量用的是全局变量,这里是以结构体的形式呈现的,因为很多情况这两个函数不在一个C里面。如果硬要写在一个C可以忽略本条。

  • 发表了主题帖: 如何使DSP数字振荡器产生移相正弦波

    引 言         产生数字式移相信号的方法有很多。传统的直接数字频率合成(DDS)移相原理是先将正弦波信号数字化,并形成一张数据表存入两片ROM芯片中,此后可通过两片。D/A转换芯片在计数器的控制下连续地循环输出该数据表,就可获得两路正弦波信号。当两片D/A转换芯片所获得的数据序列完全相同时,则转换所得到的两路正弦波信号无相位差。当两片D/A转换芯片所获得的数据序列不同时,则转换所得到的两路正弦波信号就存在着相位差。相位差的值与数据表中数据的总个数及数据地址的偏移量有关。这种处理方式的实质是将数据地址的偏移量映射为信号间的相位值。数据的偏差可以通过外部微处理器来获得相应的数字量输入,这个数值对应着正弦信号的移相角度。直接频率合成方法具有频率转换时间短、相位噪声性能好、精度高,产生的信号频率范围宽等优点,但由于需要采用地址、相位计算、访问存储器操作等环节,导致直接频率合成器结构复杂、成本高、移相分辨率低。        本文利用DSP技术,通过数值迭代方法,即用DSP数字振荡器的实现原理获得两路正弦波信号。通过仿真,硬件实现,能得到设定参数的两路正弦波输出,达到了设计目的,并具有调整方便灵活、分辨率高等特点。数值迭代方法能精确计算角度的正弦值,只需较小的存储空间,选择正弦周期中的样点数、改变样点间的延迟,能产生不同频率的波形,可利用软件改变波形幅度及相位。 1 波形及移相波形发生器的DSP实现原理       利用DSP通过运算,用叠代的方法产生正弦信号,即数字振荡器。数字振荡器的单位冲击响应为sin(nωT+θ)·u(n)即系统在δ(n)的激励下,产生振荡,输出相位为θ的正弦序列,该系统的系统函数就是冲击响应的Z变换,即         当n≥3时有:y(n)=2cosωT·y(n-1)-y(n-2)。在n≥3以后,y(n)能用y(n-1)和y(n-2)算出,这是一个递归的差分方程。因此得到如下结论:只要已知系统输出正弦信号角频率ω和采样周期T就可以得到系统差分方程,系统只需每隔T秒时间计算一次差分方程,就可得到当前正弦采样序列y(n)的值。设定的y(1)、y(2)初值不同,初始相位就不同。在设计中,主程序通过键盘输入频率及相位差等数据,在初始化时依输出信号频率、采样速率及相位差等数据先计算出两路正弦信号的初始值y1(1)、y1(2)和y2(1)y2(2),然后开放定时器中断。以后每次进入定时器中断服务程序时,利用前面的y1(1)、y1(2)和y2(1)y2(2),计算出新的y1(0)和y2(0)。虽然两次计算并输出y1(0)和y2(0)有一定的延迟,但由于DSP的高速流水线运行及McBSP高速串行输出,所引起误差将很小。 2 系统硬件实现方案         基于TMS320VC5416 DSP的两路输出移相正弦波的系统结构如图1所示。该系统的中央处理单元采用美国TI(德州仪器)公司的高性能定点数字信号处理芯片TMS320VC5416,TMS 320 VC54.16是TI公司专门针对便携式设备设计的一款低功耗、高性能定点数字信号处理器,同C54系列其它处理器相比运行速度达到160MPIS,片内RAM达到128K,程序可寻址空间达到8M,为大量数据处理提供了丰富条件。特别是VC5416提供了多种片内外设资源;软件可编程等待状态产生器、可编程锁相环时钟产生器、1个16位计时器、6通道直接内存访问控制器(DMA)、3个多通道缓冲串口(McBSP)、8位增强型HPI接口等。此外,TMS320VC5416支持C和汇编语言混合编程,高效的流水线操作和灵活的寻址方式使其特别适合高速实时信号处理。由于系统有两路正弦信号输出,系统采用两路信号分时传输方式。TLC320AD50C是TI公司出品的一块将A/D和D/A转换功能集成在一起的模拟接口芯片,采用∑-△技术在低系统成本下实现了高精度的A/D和D/A转换。该芯片由一对16 b同步串行转换通道组成,在ADC之后有一个抽取滤波器,在DAC之前有一个插值滤波器。TLC320AD50C支持主从两种工作方式,并且最多支持三个从设备。利用该特点,系统将两片TLC320AD50C串联,使其中一个为主设备另一个为从设备,通过TMS320VC5416的多通道缓冲串口McBSP实现与两片TLC320AD50C间的串行通信。TMS320VC54.16控制两片TLC320AD50C以时分复用方式将数据传送给两片TLC320AD50C进行D/A转换输出。其中AD50C1的M/S接高电平,AD50C2的M/S接低电平,并且利用VC5416的XF引脚为AD50C提供主、次通信选择信号。TLC320AD50被广泛应用于音频数据采集处理中,它可以与TMS320C54xDSP的McBSP无缝串行连接进行数据采集、存储和处理。SCLK输出时钟,DIN串行输入,DOUT串行输出,FS帧同步信号输出,对应DSP的各相应引脚。MCBSP具有特点:①串口的接收,发送时钟既可由外部设备提供,又可由内部时钟发生器提供;②帧同步信号和数据时钟信号的极性可编程,内部时钟和帧信号发生器也可由软件编程控制;③串口的信号发送和接收部分既可单独运行,又可以在一起配合工作;④CPU的中断信号和DMA的同步信号使得McBSP串口可由CPU控制运行,还可脱离CPU通过DMA直接存取内存单独运行;⑤多通道选择部分使得串口具备了多通道信号的通信能力,他的多通道接收和发送能力可达128个信道;⑥数据宽度可在8b、12b、16b、20b、24b、32b中任意选择,并可对数据进行A律和U律压缩和扩展。McBSP串口包括一个数据通道和一个控制通道,数据通道完成数据的发送和接收。McBSP通过DX引脚发送数据、DR引脚接收数据。控制通道完成的任务包括内部时钟的产生、帧同步信号的产生、对这些信号的控制以及多通路的选择等。控制通道还负责产生中断信号送往CPU,产生同步事件信号通知DMA控制器。控制信息则是通过控制通道以时钟和帧同步信号的形式传送。 3 系统软件设计及CCS仿真结果        系统软件主要由BootLoader下载程序、系统初始化、键盘显示、定时中断处理等几个模块构成。系统开始上电时首先执行BootLoader程序,将目标程序从外部FLASH中调入片内RAM中执行。       系统初始化程序完成对TMS320VC5416各控制寄存器,McBSP串口控制寄存器,定时器以及TLC320AD50C相应寄存器的初始化设置。主程序及定时中断服务程序流程图如图2所示。 设定正弦波频率为2 kHz,采样频率40 kHz,移相60度的CCS仿真波形如3所示。 4 结束语         本文提出了一种基于DSP数字振荡器产生移相正弦波的设计方法。实验结果表明系统产生的波形稳定,抗干扰能力强,频率、相位和幅度调节方便,精度高,输出频率范围为20 Hz~20 kHz,相移0~360°,移相分辨率可高达0.001度。另外系统若连接高速DA转换芯片,可大大提高输出频率范围。该设计方案简单可行、新颖实用,有推广应用价值。

  • 2019-01-10
  • 发表了主题帖: 隔离式 Δ-Σ 调制器的问题: 我的系统是否足够快,能够进行短路保护?

    电流隔离是许多工业应用中的一项关键要求。隔离提供了诸如断开噪声接地环路等技术优势,而且其还可避免终端用户和敏感设备遭受具有潜在危险性的高电压和瞬变。 按图 1 所示可以构建一个隔离型电流监视采集系统:利用一个电流分流器将输入电流转换为模拟电压,并把该电压馈送至一个模数转换器 (ADC)。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/3286.4606_5F00_Fig1_5F00_jpg_2D00_550x0.jpg图 1:采用 ADC 和数字隔离器的隔离型数据采集系统 假如能够构建一个如图 1 所示的系统,那么它就面对着如下的问题:为什么要用一个隔离型 Δ-Σ 调制器来取代全 ADC 与数字隔离器的组合呢?为什么要选择一个如图 2 中所示的系统呢? https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/4274.3005_5F00_Fig2_5F00_jpg_2D00_550x0.jpg图2:采用一个Δ-Σ调制器的隔离型数据采集系统 虽然隔离型采集系统的首要任务是在所需的数据速率下实现高精度和准确度,但是利用图 2 中给出的系统能实现一种辅助功能。可以在 Δ-Σ 调制位流上实现两个数字信号处理路径 (DSP)。例如:假设主路径利用一个 256 的因子对输入位流(比如:在 20 MHz 频率下提供的)进行抽取。这个主要的 DSP 路径可在 78.1 kSPS 的采集速率下提供高分辨率的电流测量。 接着,可实现一个辅助的 DSP 路径,其目标是在发生短路事件时生成一个报警信号。这个辅助的 DSP 路径接受由主路径实施并行处理的相同 Δ-Σ 调制位流,但其采用的是一个低得多的抽取因子。例如:倘若辅助抽取因子选为 4,则用户获得一个 5 MSPS 的辅助信号输出。将该信号实时地与一个预设阈值进行比较;如果此阈值被超过,那么将发出一个命令信号以断开安全继电器或切断敏感组件的供电。单个 Δ-Σ 调制器允许用户利用极少的组件实现这两个 DSP 路径。 需要提及在选择一个较低抽取因子时所做的折衷,这一点很重要:较低的抽取因子(也被称为“过采样比 [OSR]”)降低了滤波器输出的分辨率。图 3 示出了针对某一给定的 OSR 以及 TMS320F28377D 中各种可用滤波器类型的系统分辨率(用“有效位数 [ENOB]”来表达)。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/2654.7002_5F00_Fig3_5F00_jpg_2D00_550x0.jpg图3:针对TMS320F28377D 中给定 OSR 的系统分辨率 两种系统架构(图 1 和 2)均实现了高精度。主要的差异是可利用单个 AMC1304M25 隔离型 Δ-Σ 调制器来实现双重(a) 高精度和 b) 报警信号)发布功能。替代型架构需要使用两个 ADC:一个运行于 78.1 kSPS 的高精度 ADC 和另一个运行在 5 MSPS 的较低精度转换器。 把隔离势垒集成到单颗 IC 中使得基于 AMC1304M25 的解决方案能够节省板级空间并减少组件数量,从而简化电路板装配、提高可靠性及降低总体解决方案成本。 图 2 给出的解决方案在一款新型电流检测参考设计中进行了展示:TIPD165。以该参考设计为指导,系统设计人员将拥有一个对 AMC1304M25 和  TMS320F28377D 进行实验的完整平台。TIPD165 中包括的图形用户界面 (GUI) 和固件可在设计人员启动隔离式电流检测设计时为其提供进一步的帮助。 图 4 示出了该 GUI 的图形面板。用户可以在这里观测主要的 AC 和 DC 性能。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/1643.0333_5F00_fig4_5F00_jpg_2D00_550x0.jpg图4:TIPD165 GUI 的图形面板 正如在 TIPD165 中展示的那样,AMC1304M25 和 TMS320F28377D 提供了一个用于隔离型采集系统的稳健平台。AMC1304M25 的隔离规格与 TMS320F28377D 的处理能力相结合,使得设计人员能够打造出可快速响应过流事件的高精度系统。

  • 发表了主题帖: Σ-Δ ADC数字滤波器类型

    有没有想过Σ-Δ模数转换器(ADC)如何才能在不同带宽下获得如此高的分辨率?秘诀就在于数字滤波器。Σ-Δ ADC之所以与其他类型的数据转换器不同,是因为它们通常集成有数字滤波器。本系列博文分为三部分,我将在第一部分中讨论数字滤波器的用途,以及常用于Σ-Δ ADC的一些数字滤波器。要想理解数字滤波器在Σ-Δ模数转换中如此重要的原因,关键的一点是需要对Σ-Δ调制器有一个基本了解。Joseph Wu写了一篇非常有用的Precision Hub模拟精密技术杂谈博文,文中解释了模拟输入信号转变成数字比特流的过程。当客户在Σ-Δ调制器中绘制量化噪声的频谱时,将看到频率越高时量化噪声越密集。这是Σ-Δ ADC为众人所知的臭名昭著的噪声整形。为了降低量化噪声,客户将调制器输出馈至低通滤波器。图1所示为在被称为sinc滤波器的Σ-Δ模数转换器中发现的,通过常见的低通数字滤波器响应绘制的量化噪声图(它的名字源于其sin(x)/ x频率响应)。 大小(dB)https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/4011.1.jpg.png 频率(fmod) 图1:Σ-Δ量化噪声和Sinc低通滤波器的频谱 Sinc滤波器,虽然极为常见,但并非Σ-Δ ADC附带的唯一一种数字低通滤波器。例如,有些ADC(如ADS1220)会增加一个额外的50Hz / 60Hz陷波滤波器,用于具有大量电力线干扰的应用。从另一方面讲,ADS127L01具有用于更高频率应用的宽带宽平通带数字滤波器。正如我的同事Ryan Andrews在其关于抗混叠滤波器的博文中解释道,Σ-Δ ADC中的数字滤波器具有另外一项抽取功能。这些滤波器以低很多的速率(fDR)通过被称为过采样率(OSR)的因子抽取调制器采样频率和输出数据。综合OSR和滤波器类型来确定数字滤波器的输出带宽。大过采样率会产生小型滤波器带宽,从而转化为极好的隔音性能,简化了抗混叠前端,并降低了主机控制器的接口速度。大多数数字滤波器具有有限脉冲响应(FIR)。这些滤波器本质上是稳定的,易于通过线性相位响应进行设计。让我们来对比Σ-Δ ADC中的两种FIR滤波器。第一种是ADS127L01中的宽带滤波器。第二种是一个典型的三阶正弦响应滤波器,或sinc3。图2和图3并排绘制这些响应。大小(dB)https://e2echina.ti.com/resized-image.ashx/__size/250x200/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/5873.2.jpg.png频率(fDR)大小(dB)https://e2echina.ti.com/resized-image.ashx/__size/250x200/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/3716.3.png频率(fDR)图2:宽带滤波器的频率响应图3:Sinc3的频率响应 很快,客户可以清楚地看到在交流(AC)测量应用中使用宽带滤波器的优点。数据率(fDR/2)的奈奎斯特带宽之前其近0 dB的增益确保了在通带频率上不会出现信号功率损耗。急剧升降的过渡带限制了混叠。另一方面,sinc3滤波器通过0.262 x fDR及fDR/2之后的缓慢过渡,将信号衰减至-3dB,这样会将更多的带外噪声调入相关的带宽。表面上看,宽带FIR滤波器将是任何应用的理想选择;然而,要想获得这一出色的频域性能需要付出代价。宽带滤波器和sinc滤波器之间的权衡在于时域。宽带滤波器是一个非常高阶的滤波器,这说明它在收到一个阶跃输入后,需要花费很长时间才能得出一个最终值。在ADS127L01的宽带滤波器中,客户将不得不等待84次转换才能收到一个固定输出。输入处出现一次阶跃后,sinc3滤波器会通过三次转换固定下来,让客户通过多个传感器进行循环。所有FIR滤波器都需要在频率响应和延迟之间进行权衡。

  • 发表了主题帖: Δ-Σ模数转换器基础知识: 了解 Δ-Σ 调制器

    Δ-Σ ADC由Δ-Σ调制器和数字滤波器构成。调制器将模拟输入转换为数字比特流,而数字滤波器将比特流转换为表示模拟输入幅度的数据字。让我们来看看调制器是如何工作的,首先从一阶Δ-Σ调制器拓扑结构的基本分析开始,如图1所示。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/0243.6153.Figure-1.png_2D00_700x0.png图 1:Δ-Σ调制器内部框图 调制器根据调制器时钟运行,决定了输入的采样间隔。调制循环通过对输入采样和1位DAC之间的差分进行积分而开始。比较器根据积分器值确定下一个调制器输出。根据比较器的输出状态,1位DAC产生与ADC的正或负基准电压相等的电压。如果调制器输出为1,则从输入中减去基准电压。如果调制器输出为0,则在输入中加上基准电压。在每个调制器时钟脉冲,调制器完成一个完整的周期并产生一个新的输出。当调制器时钟继续运行时,每个调制器时钟脉冲将产生另一个调制器输出脉冲。所得到的输出比特流成为与基准电压成比例的输入电压的另一种表示。图2显示了输入正弦波和得到的调制器输出比特流,假设基准电压为1V。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/1614.1108.Figure-2.png_2D00_700x0.png图 2:正弦波输入(上图)和调制输出比特流(下图) 当输入接近1V时,调制器的比特流的1s密度接近100%。相反,当输入接近-1V时,比特流1s密度接近0%。当输入为0V时,1s密度为50%。因此,可以在不超出调制器范围的情况下测量基准电压和负基准电压之间的输入电压。那么通过将输入转换为比特流调制器实现了什么?观察调制器的频谱内,输入电压和采样数字信号之间的误差被建模为量化噪声,如图3a所示。采用二了简单的量化,误差频谱密度是从DC到采样频率(fS)的白噪声除以2。通过使用Δ-Σ调制,量化误差频谱密度被调至更高的频率,如图3b所示。低通数字滤波器保留具有较高分辨率的输入信号,因为量化噪声已经移动到数字滤波器的通带之外。使用Δ-Σ调制,我们减少了量化噪声,实现了更高的分辨率。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-14/7245.2016_2D00_12_2D00_16_5F00_171100.png 具有额外前馈和反馈路径的多阶的不同调制器拓扑结构可以提供比上述基本示例更好的噪声整形。不同的数字滤波器提取原始信号,以更高的测量分辨率加速ADC。通过将这种复杂的拓扑结构分解到基本水平,您可以看到Δ-Σ调制器的工作原理:调制器对输入信号进行采样,将其与基准进行比较,输出与基准相比与输入信号的幅度成比例的1s的比特流。请留意下个月的Precision Hub模拟精密技术杂谈,届时我将讨论如何结合调制器和数字滤波器以获得更大的测量分辨率。

  • 发表了主题帖: CMOS技术实现的微型化毫米波传感器

          大多数商用雷达系统,特别是高级驾驶员辅助系统 (ADAS) 中的雷达系统,均基于锗硅(SiGe)技术。目前的高端车辆都有一个多芯片SiGe雷达系统。虽然基于SiGe技术的77GHz汽车雷达系统满足自适应巡航控制时的高速度要求,但它们体积过大、过于笨重,占用了大量电路板空间。       随着车辆中雷达传感器数量的不断攀升,目前车辆中至少有10个雷达传感器(前置、后置和车角),空间上的限制就要求每个传感器必须体积更小、功耗更低,并且性价比更高。某些正处于开发阶段的现有雷达系统将促使发射器、接收器、时钟和基带功能集成在一个单芯片内,而这将把前端芯片的数量从4个减少到1个,不过这只适用于雷达前端。        通过充分利用互补金属氧化物半导体(CMOS)技术,并将嵌入式微控制器 (MCU)和数字信号处理(DSP)以及智能雷达前端集成在内,TI已经将集成度提升至新高度。前端具有处理功能将尽可能降低雷达系统尺寸、功率、外形尺寸和成本,从而进一步实现车辆内多个雷达系统的安装。 https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-22/8712.Figure-1-single-chip-integration-with-CMOS.png_2D00_1230x0.png图1:由CMOS实现的单芯片集成       CMOS技术的传统优势包括更高的晶体管密度和更低功率。CMOS内的数字缩放降低了功率,缩小了尺寸,并且提高了每个节点的性能。在数字晶体管改进的推动下,CMOS的速度不断提高,现已足以满足79GHz ADAS应用的需要了。       79GHz波段提供4GHz带宽,这对更高范围的分辨率至关重要。未来的雷达系统还将需要对短距离的支持,将更佳的角分辨率转化为雷达系统内的更多天线。采用CMOS技术的TI传感器能够支持此项扩展能力,实现高容量的大批量生产。        CMOS技术进一步提高了TI在模拟组件中嵌入数字功能的能力,从而实现了在雷达系统部署方面的全新系统配置和拓扑。例如,TI单芯片毫米波(mmWave)传感器内的嵌入式MCU可实现射频(RF)和模拟子系统的半自主控制。TI的CMOS传感器为模拟组件提供数字辅助,以便适应环境和生产过程中的变化,同时保持灵活性和稳健耐用性,数字辅助能够灵活生成调频信号并能实现实时高级自监控。        一个雷达系统的动态范围取决于接收器噪底,以及在保险杠反射所导致的自干扰下的耐受能力。而这在很大程度上取决于架构和系统能力,这样就使一个CMOS系统——具有更宽的中频(IF)带宽、更多信道和精确的低噪声线性闭环调频信号生成——对于特定的雷达应用具有出色的系统级性能。        CMOS技术改变了毫米波传感器的设计,并嵌入更高的智能化和功能性。CMOS技术已经使TI能够提供高性能、低功率毫米波传感器产品组合,涵盖了从高性能雷达前端到单芯片雷达的整个范围。

  • 发表了主题帖: AMIC110 SoC让工业通信变得简单

    工业以太网协议是工厂自动化的一个重要组成部分。现在出台了许多协议标准,包括EtherCAT、Profinet、Powerlink、以太网/工业协议(IP)和Sercos III。拥有众多不同协议使开发可用于多个不同网络的解决方案更具挑战性。一个解决方案是拥有一个可针对不同协议进行再编程的单个设备,如TI最新推出的AMIC110片上系统(SoC)。 TI Sitara™ARM®处理器通过可编程实时单元工业通信子系统(PRU-ICSS)实现10多种工业通信标准。如果设计中已存在现有的应用处理器,添加全功能ARM®处理器则可能不切实际。若是这种情况,您可利用现有产品,还可通过添加像AMIC110 SoC这样的通信处理器来实现PRU-ICSS的功能。尽管AMIC110SoC包含ARMCortex®-A8内核,但它可运行以太网堆栈,而非作为主处理器。 作为通信处理器,AMIC110 SoC为静态解决方案提供了灵活的替代方案。其中一个优点是AMIC110 SoC的软件可编程性使您可以运行不同的通信标准,而非仅针对一种标准。这使得在使用不同协议的不同项目中重用同一设备成为可能。如果协议发布了功能变更,或者在新的协议发布后需要完全对SoC进行重新编程,那么可重新编程性便使得升级也变得更加容易。这些优点使得AMIC110 SoC成为向设备添加工业通信的绝佳方式。 例如,一个电机控制应用程序可使用C2000™微控制器(MCU)来控制电机,如图1所示。为了添加像EtherCAT这样的协议,C2000 MCU可通过串行外设接口(SPI)与AMIC110进行通信,而AMIC110 SoC将处理至网络其余部分的协议基通信。https://e2echina.ti.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-01-22/3583.2017_2D00_06_2D00_07_5F00_155956.png图1:使用AMIC110和C2000实现电机控制的示例 AMIC110 SoC是Sitara处理器系列的一部分,并且延续该系列的众多优点,如使用处理器软件开发工具包(SDK)作为标准软件平台。处理器SDK可轻松地在Sitara处理器之间迁移软件,这可减少新处理器的学习时间,并使您能够充分利用现有的产品。

  • 发表了主题帖: STM32F4系列MCU独立看门狗IWDG的应用

          为了提搞系统的可靠性,STM32F4系列MCU有一个独立看门狗(IWDG)和一个窗口看门狗(WWDG)。今天做的实验是关于独立看门狗的。          独立看门狗使用的时钟源是内部低速振荡器LSI。因为LSE可能没接,HSE可能坏点,HSE耗着的时候HSI却观点了。。。诸多原因,LSI是最好的独立看门狗时钟。 STM32F4系列MCU独立看门狗IWDG的应用 【IWDG主要特性】 1、独立的向下计数器 2、内部RC振荡器作为时钟源 3、当计数器值减到0时,复位MCU 【IWDG配置步骤】 1、设置KR寄存器,为向PR和RLR写入数据做准备。向KR写入0x5555使能写入PR和RLR 2、写入预分频值和重装载值。预分频是对LSI进行分频,重装载值是每次重新计数的开始值。 3、向KR写入0xAAAA,使能计数。 4、向KR写入0x5555,重新开始计数。否则计数到0就会reset。 【代码实现】 本实验依赖于前面的LED实验。实验第一步的现象是LED反复闪烁。第二步现象是LED亮一下后熄灭。 第一部分: int main() { NVIC_Config(); LED_Init(); LEDOn(LED1); delay_ms(500); LEDOff(LED1); IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能写入PR和RLR IWDG_SetPrescaler(IWDG_Prescaler_128); //写入PR预分频值 IWDG_SetReload(100); //写入RLR IWDG_Enable();//KR写入0xCCCC while(1) { IWDG_ReloadCounter(); //KR写入0x5555 重新开始计数,不让复位 } } 在这次实验中我们看到LED亮一下就保持常暗。说明MCU没有被复位。 第二部分,我们不重装RLR计数器,看看呢个不能复位mcu int main() { NVIC_Config(); LED_Init(); LEDOn(LED1); delay_ms(500); LEDOff(LED1); IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能写入PR和RLR IWDG_SetPrescaler(IWDG_Prescaler_32); //写入PR预分频值 IWDG_SetReload(100); //写入RLR IWDG_Enable();//KR写入0xCCCC while(1) { //等待mcu被IWDG复位 } } 这次可以看到LED在闪烁了。

  • 发表了主题帖: MCU内部的RAM上电之后的初始值相关问题

          MCU内部的RAM上电之后的初始值到底是什么,有什么特性和规律。今天笔者就以使用RH850F1K的过程中遇到的几个问题与大家做一个交流。        首先我们明确一个问题,我们都知道,根据RAM的特性,MCU每次上电之后RAM里面的值是随机的。也就是说RAM上电后的初始值可以是0xAA,也可以是0x55,也可以是其它任何的值,这个都是正常的。明确了这个基本原理之后,我们来看一下下面这个跟RAM的初始值的使用相关的一个问题。 浅析MCU内部的RAM上电之后的初始值相关问题      最近有工程师在开发的汽车娱乐系统中遇到了一种情况,就是他在使用RH850F1K的过程中,发现每次上电后RAM的值好像都是固定的。按照软件设计的初衷,他想通过判断RAM的值从而知道这次复位是掉电复位还是MCU内部复位——比如“看门狗”复位。如果是掉电复位,则对RAM进行初始化;如果是MCU内部复位,则不对RAM进行初始化,从而可以保持用户之前的一些设置,比如频道、界面信息等。 大致的设计思路和流程如下: MCU复位后,软件会判断某个变量的值:如果不是0x55,就认为这是上电复位,所有的RAM需要初始化,并把该变量的值写为0x55;如果是0x55,就认为这是“看门狗”复位,这时候则不改变一些变量的值,比如记录里程相关的数据。相关的C语言代码为: if (variable != 0x55) { 初始化所有变量; variable = 0x55; } else { 只改变部分变量的值; } 在测试的过程中,测试工程师发现了一个问题:对于99%的MCU来讲,上述的逻辑都是没有问题的,但是对于个别MCU却存在固定性的问题。 按照设计的初衷,本来我们认为上电后RAM的值是随机的,但是对于某些个别MCU来讲,测试工程师发现上电后RAM的值会固定的是0x55,或者出现0x55的几率非常高。       针对这个现象,笔者也从单个MCU的特性方面做了解释:首先我们还是回到文章最初提到的问题,根据RAM的特性,上电后RAM是任何值都是正常的,基于这个前提,我们可以说测试工程师遇到的现象是正常的。那么为什么个别MCU的RAM上电后会偏向于某个特定值呢?我们知道半导体器件的设计是非常复杂的,外观很小的一个芯片都是芯片内部数百万计的各种极其小的元器件搭建而成的,而这些的原材料基本都是硅。对于每个特定的芯片而言,其特性数据都是有一些偏好的,也包括上电后RAM的初始值,所以当我们看每个MCU的电气特性数据的时候,这些数据基本都是一个范围值,而不是确定的值。      另外,上面软件本身的设计也是有缺陷的,或者说鲁棒性不好。假定上电后RAM的初始值是完全随机的,那么这样总会碰到随机值恰好是0x55的情况。基于这种考虑,我建议软件工程师重新设计了判断的条件。比如判断RAM若干不连续地址的值,并且使用校验的算法,比如比较简单的校验和,这样可靠性就大大提高了。       曾经多个客户遇到过类似的问题,这个问题也具有一定的普遍性,除了前面提到的汽车娱乐系统,在车身、仪表,甚至工业应用中的电表等都会涉及到,希望这篇文章能够帮助设计工程师少走一些弯路。

  • 发表了主题帖: 单片机中如何用C语言实现查表找到对应的值

    第一个是查表法 比方说我有三个数据 char code table={0x01,0x02,0x03}分别对应0xa,0xb,0xc,请问如何用C语言实现查表找到对应的值呢?请给位大虾写出具体的语法实现,要简洁明了。 第二个问题是:比方说我有一数据 char data=0xa2 ;我要串行发送出去,那么我采用从高位发送,然后左移8次分别发出,请问如何实现?若是采用data《《1这样的语法,每次左移出去的高位去哪了呢?在CY位?那么任何单片机都有CY寄存器?况且都是左移,data《《1,什么时候高位就会移入CY,什么时候就是丢弃不要呢? 单片机中如何用C语言实现查表找到对应的值 第一个问题: 比如用查表法将结果保存到变量i中,查表变量为x,则i = table[x],记住C语言里面数组是从0开始的,比如说上面的0x01就是table[0],0x02是table[1],以此类推。 再说第二个问题: 比如说从P1.0口发送出去,则可以写为 sbit OUT = P1^0;//定义OUT为P1.0口,这样今后好写程序 char i; for(i = 0;i 《 8;i++) { OUT = data & 0x80;//因为高位在前,将它写成二进制就明白了 data 《《= 1; } 上面的程序就能搞定了; 应该是所有的单片机都有CY位(不知道浮点DSP有没有); C语言中左移和右移之后低位或高位自动补零,CY位也保持为零(视编译器而定,这个得看编译器手册),有些编译器提供了循环移位的函数;

  • 发表了主题帖: DSP的IIR数字滤波器实现程序源码

    DSP的IIR数字滤波器实现程序源码 附录(C程序源码): #include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File #include "DSP2833x_Examples.h"   // DSP2833x Examples Include File #include  <math.h> #define IIRNUMBER 2 #define SIGNAL1F 1000 #define SIGNAL2F 4500 #define SAMPLEF  10000 #define PI       3.1415926 float InputWave(); float IIR(); float fBn[IIRNUMBER]={ 0.0,0.7757 }; float fAn[IIRNUMBER]={ 0.1122,0.1122 }; float fXn[IIRNUMBER]={ 0.0 }; float fYn[IIRNUMBER]={ 0.0 }; float fInput,fOutput; float fSignal1,fSignal2; float fStepSignal1,fStepSignal2; float f2PI; int i; float fin[256],fout[256]; //输入fIn毛刺正弦波,输出fOut较光滑正弦波,Graph: 256,32-bit floating integer, int nIn,nOut; main() {     nIn=0; nOut=0;     fInput=fOutput=0;     f2PI=2*PI;     fSignal1=0.0;     fSignal2=PI*0.1; //  fStepSignal1=2*PI/30; //  fStepSignal2=2*PI*1.4;     fStepSignal1=2*PI/50;     fStepSignal2=2*PI/2.5;     while ( 1 )     {         fInput=InputWave();         fin[nIn]=fInput;         nIn++; nIn%=256;         fOutput=IIR();         fout[nOut]=fOutput;         nOut++;             // break point         if ( nOut>=256 )         {             nOut=0;         }     } } float InputWave() {     for ( i=IIRNUMBER-1;i>0;i-- )     {         fXn=fXn[i-1];         fYn=fYn[i-1];     }     fXn[0]=sin((double)fSignal1)+cos((double)fSignal2)/6.0;     fYn[0]=0.0;     fSignal1+=fStepSignal1;     if ( fSignal1>=f2PI )   fSignal1-=f2PI;     fSignal2+=fStepSignal2;     if ( fSignal2>=f2PI )   fSignal2-=f2PI;     return(fXn[0]); } float IIR() {     float fSum;     fSum=0.0;     for ( i=0;i<IIRNUMBER;i++ )     {         fSum+=(fXn*fAn);         fSum+=(fYn*fBn);     }     return(fSum); } 复制代码

  • 发表了主题帖: TMS320F28335程序SVPWM源程序

    单片机源程序如下: //***************************************************/ //文件名:SVPWM.c //功能:调用28335内部PWM模块生成SVPWM输出测试文件 //说明:输入信息采用结构体,使用时改变结构体指针即可改变输入信号。 //     InitSvpwm()函数提供PWM模块初始化以及相应PIE中断的配置。 //     通过park逆变换得到静止平面坐标系下的电压信号。 //     在PWM定时器下溢中断中更新比较器的值,即每个PWM周期更新一次 //****************************************************/ #include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File #include "DSP2833x_Examples.h"   // DSP2833x Examples Include File #include "math.h" #include "float.h"         extern Uint16 RamfuncsRunStart;         extern Uint16 RamfuncsLoadStart;         extern Uint16 RamfuncsLoadEnd;          typedef struct {    float ds;              // 静止平面坐标系下电压信号    float qs;    float ang;             // 电气角度 电气角度=机械角度*极对数    float de;              // 旋转坐标系下电压信号    float qe; }IPARK;   IPARK ipark1={0,0,0,0.3,0.4}; //  IPARK *v=&ipark1;       //改变此处结构体指针改变输入 void InitSvpwm(void); void InitEPwm1(void); void InitEPwm2(void); void InitEPwm3(void); interrupt void epwm1_isr(void); void ipark(IPARK *v); void svgen(IPARK *v); #define PRD  7500                // PWM周期寄存器 #define PI 3.1415926 float tmr1,tmr2,tmr3; void main(void) {    InitSysCtrl();    DINT;    InitPieCtrl();    IER = 0x0000;    IFR = 0x0000;       InitPieVectTable();         MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);                        //Flash operation<F28335.cmd>         InitFlash();                          InitSvpwm();    for(;;)    {        asm("          NOP");    } } void InitSvpwm(void) {      InitEPwm1Gpio();    InitEPwm2Gpio();    InitEPwm3Gpio();    EALLOW;    PieVectTable.EPWM1_INT = &epwm1_isr;       EDIS;    EALLOW;    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;    EDIS;    InitEPwm1();    InitEPwm2();    InitEPwm3();    EALLOW;    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;    EDIS;    IER |= M_INT3; // 使能中断 EPWM INT1 位于PIE中断分组3.1    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;    EINT;    ERTM; } interrupt void epwm1_isr(void) {    // 更新 CMPA 和 CMPB 寄存器值    svgen(&ipark1);    EPwm1Regs.CMPA.half.CMPA=tmr1;    EPwm2Regs.CMPA.half.CMPA=tmr2;    EPwm3Regs.CMPA.half.CMPA=tmr3;    EPwm1Regs.CMPB=tmr1;    EPwm2Regs.CMPB=tmr2;    EPwm3Regs.CMPB=tmr3;        // 清除中断标志    EPwm1Regs.ETCLR.bit.INT = 1;    // 清除中断响应    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; } void ipark(IPARK *v) {   float  ang;   ang=(v->ang/360)*2*PI;                    //角度转化为弧度   v->ds=v->de*cos(ang)-v->qe*sin(ang);      //得到静止平面坐标系下d轴电压   v->qs=v->qe*cos(ang)+v->de*sin(ang);      //得到静止平面坐标系下q轴电压 } void svgen(IPARK *v) {    float Va,Vb,Vc,t1,t2,Ta,Tb,Tc;    Uint32 sector=0;                                               // sector=a+2b+4c 扇区状态标示 注意:setor的值1~6与扇区不是顺序对应    ipark(v);    Va=v->qs;                                                      // Va = Uq    Vb=(-0.5) * v->qs + (0.8660254) * v->ds;                       // Vb = 1/2*(sqrt(3)*Ud - Uq)         sqrt(3)/2=0.866    Vc=(-0.5) * v->qs - (0.8660254) * v->ds;                       // Vc = -1/2*(sqrt(3)Ud + Uq)    if(Va>0.0000001)                                               // 判断属于哪个扇区            sector=1;                                                      // Va>0 则 a=1;否则a=0    if(Vb>0.0000001)                                               //    sector=sector+2;                                               // Vb>0 则 b=1;否则b=0    if(Vc>0.0000001)                                               //    sector=sector+4;                                               // Vc>0 则 c=1; 否则c=0    Va=v->qs;                                                         Vb=(-0.5) * v->qs + (0.8660254) * v->ds;                         Vc=(-0.5) * v->qs - (0.8660254) * v->ds;      switch(sector){      case 1:                               //sector==1 对应扇区II        t1=Vc;        t2=Vb;        Tb=(0.25)*(1-t1-t2);        Ta=Tb+(0.5)*t1;        Tc=Ta+(0.5)*t2;            break;      case 2:                               //sector==2 对应扇区VI        t1=Vb;        t2=-Va;        Ta=(0.25)*(1-t1-t2);        Tc=Ta+(0.5)*t1;        Tb=Tc+(0.5)*t2;        break;      case 3:                               //sector==3 对应扇区I        t1=-Vc;        t2=Va;        Ta=(0.25)*(1-t1-t2);        Tb=Ta+(0.5)*t1;        Tc=Tb+(0.5)*t2;        break;      case 4:                               //sector==4 对应扇区IV        t1=-Va;        t2=Vc;        Tc=(0.25)*(1-t1-t2);        Tb=Tc+(0.5)*t1;        Ta=Tb+(0.5)*t2;        break;      case 5:                               //sector==5 对应扇区III        t1=Va;        t2=-Vb;        Tb=(0.25)*(1-t1-t2);        Tc=Tb+(0.5)*t1;        Ta=Tc+(0.5)*t2;        break;      case 6:                              //sector==6 对应扇区V           t1=-Vb;        t2=-Vc;        Tc=(0.25)*(1-t1-t2);        Ta=Tc+(0.5)*t1;        Tb=Ta+(0.5)*t2;        break;      default:                             //sector=0和sector=7时错误        Ta=0.5;        Tb=0.5;        Tc=0.5;    }    tmr1=Ta*PRD;    tmr2=Tb*PRD;    tmr3=Tc*PRD; } void InitEPwm1() {    // 配置时钟    EPwm1Regs.TBCTL.bit.CTRMODE = 0x2;             // 增减计数模式    EPwm1Regs.TBPRD = PRD;                         // 设置周期    EPwm1Regs.TBCTL.bit.PHSEN = 0x0;               // 禁用相位加载同步    EPwm1Regs.TBPHS.half.TBPHS = 0x0000;           // 相位初值    EPwm1Regs.TBCTR = 0x0000;                      // 计数初值    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x1;           // TBCLK = SYSCLKOUT / (HSPCLKDIV × CLKDIV)    EPwm1Regs.TBCTL.bit.CLKDIV = 0x1;    // 配置比较寄存器    EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0x0;          //使用阴影寄存器          EPwm1Regs.CMPCTL.bit.SHDWBMODE = 0x0;    EPwm1Regs.CMPCTL.bit.LOADAMODE = 0x0;          //计数器值为0时更新比较器值    EPwm1Regs.CMPCTL.bit.LOADBMODE = 0x0;    // 设置比较器初值    EPwm1Regs.CMPA.half.CMPA = 1875;                   EPwm1Regs.CMPB = 1875;                            // 模式设定    EPwm1Regs.AQCTLA.bit.ZRO = 0x1;               // 等于0时输出低    EPwm1Regs.AQCTLA.bit.CAU = 0x3;               // 计数值=比较值时输出取反    EPwm1Regs.AQCTLB.bit.ZRO = 0x2;               // 等于0时输出高    EPwm1Regs.AQCTLB.bit.CBU = 0x3;               // 计数值=比较值时输出取反    // 配置中断    EPwm1Regs.ETSEL.bit.INTSEL = 0x1;             // 计数值到0触发事件    EPwm1Regs.ETSEL.bit.INTEN = 1;                // 使能中断    EPwm1Regs.ETPS.bit.INTPRD = 0x1;              // 每次事件发生都触发中断 } void InitEPwm2() {    EPwm2Regs.TBCTL.bit.CTRMODE = 0x2;            EPwm2Regs.TBPRD = PRD;                      EPwm2Regs.TBCTL.bit.PHSEN = 0x0;             EPwm2Regs.TBPHS.half.TBPHS = 0x0000;            EPwm2Regs.TBCTR = 0x0000;                      EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0x1;         EPwm2Regs.TBCTL.bit.CLKDIV = 0x1;    EPwm2Regs.CMPCTL.bit.SHDWAMODE = 0x0;             EPwm2Regs.CMPCTL.bit.SHDWBMODE = 0x0;    EPwm2Regs.CMPCTL.bit.LOADAMODE = 0x0;       EPwm2Regs.CMPCTL.bit.LOADBMODE = 0x0;    EPwm2Regs.CMPA.half.CMPA = 1875;                   EPwm2Regs.CMPB = 1875;                            EPwm2Regs.AQCTLA.bit.ZRO = 0x1;                            EPwm2Regs.AQCTLA.bit.CAU = 0x3;                   EPwm2Regs.AQCTLB.bit.ZRO = 0x2;                EPwm2Regs.AQCTLB.bit.CBU = 0x3;                         EPwm2Regs.ETSEL.bit.INTEN = 0;                 //屏蔽中断                          } void InitEPwm3(void) {    EPwm3Regs.TBCTL.bit.CTRMODE = 0x2;             EPwm3Regs.TBPRD = PRD;                         EPwm3Regs.TBCTL.bit.PHSEN = 0x0;                EPwm3Regs.TBPHS.half.TBPHS = 0x0000;            EPwm3Regs.TBCTR = 0x0000;                     ……………………

  • 发表了主题帖: TI C66x DSP 指令集的 跳转指令B

    跳转指令用于实现程序流程的跳转,在 ARM (同样在TI C66x DSP)程序中有两种方法可以实现程序流程的跳转: —使用专门的跳转指令(如B指令)。 —直接向程序计数器 PC写入跳转地址值。 通过向程序计数器 PC写入跳转地址值,可以实现在 4GB的地址空间中的任意跳转,在跳转之前结合使用MOV LR,PC等类似指令,可以保存将来的返回地址值,从而实现在 4GB连续的线性地址空间的子程序调用。 ARM指令集中的跳转指令可以完成从当前指令向前或向后的 32MB的地址空间的跳转,包括以下4条指令: — B   跳转指令(TI C66x DSP指令集也有该指令) B 指令的格式为: B  目标地址; //程序跳转到目标地址处执行 B   Label          //程序无条件跳转到标号Label处执行 B指令是最简单的跳转指令。一旦遇到一个 B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行,并需要重新装入PC(程序计数器),使执行流水线中断。注意存储在跳转指令中的实际值是相对当前 PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26位(前后 32MB的地址空间)。

  • 发表了主题帖: TI C66x DSP 指令集 -之- ADDKPC

    ADDKPC指令的作用是通过一条指令实现返回地址的保存与nop指令的执行。在调用B指令实现真正跳转前,要保存下一条指令的地址(为了执行完跳转程序后,能够返回),并同时执行n个nop指令。该指令有助于减小设置函数调用的返回地址时使用的指令数。 如下面的汇编代码,未使用ADDKPC指令时,在B指令后要保存LABEL的地址到B3寄存器(因为B指令在5个cycle后才会起作用,所以保存LABEL地址的两条指令会执行到,因为只需2个cycle),然后执行3个nop,这样在B指令后,共用了5个cycle,下个cycle B指令就是真正起作用,跳转到func执行;使用ADDKPC指令后,只需一条指令即可实现地址的保存与NOP的执行,ADDKPC指令使用一个cycle,再执行4个nop,也是共5个cycle,之后跳转到func执行。 ADDKPC的用法:ADDKPC label, reg, n  //label是标签的地址,reg是寄存器,n是执行nop数 TI C66x DSP 汇编: 如上图,第一条指令执行B跳转指令,B指令后,执行了一个nop(1个cycle),然后执行两个ADD指令(2个cycle),然后在一个cycle同时执行OR与ADDAW指令(||所在行的执令会与他前面的那条指令同时执行,所以占用1个cycle),最后三条指令ADDAW,ADDAW,ADDKPC会同时执行(1个cycle,并在ADDKPC指令中保存CacluateEquWeightsIRC_2PIPE函数的返回地址),所以B指令后共用了5个cycle,在第6个cycle后,就会真正的跳转了,在CacluateEquWeightsIRC_2PIPE函数汇编代码的最后,会直接跳到B3地址处。B3寄存器应该是编译器默认的保存返回地址的寄存器。

  • 发表了主题帖: 使用SIMD并行处理多个数据的运算几个注意事项

    C6000流水线 一个指令操作的完成实际上要经历取指、译码、执行三个阶段的多个过程才能实现,TI提供软件流水编排来让多个“工种”同时对多个操作进行流水式的处理,大大提高了运算的吞吐能力。 C64x+, C674x和 C66x系列内核还增加了软件流水循环缓存(SPLOOP buffer)单元,使得软件流水能更快速地加载数据,并可以被暂时打断。 However, the SPLOOP buffer cannot be used to handle loops that exceed 14 execute packets For complex loops, such as nested loops, conditional branches inside loops, and function calls inside loops, the effectiveness of the compiler may be compromised. SIMD(Single Instruction, Multiple Data) C6000支持单指令多数据存取,仅一条指令,就能一次性操作64bit的数据,这64bit可以由多个双字/字/字节数据组成。 C6000 C Compiler 编译器是代码优化工作的最终执行者,它分析代码的相关信息,并做出优化的决策。但有时,编译器无法仅通过分析代码获得一些对于优化很重要的信息,这时编程者主动提供必要的信息给编译器就显得非常重要。 我们可以通过编译选项、关键词以及pragma编译指示来告知编译器和优化有关的信息。同时,还可以利用编译器的优化返回信息,进一步调整优化策略。 其它 内嵌函数 TI提供一套内嵌函数供编程者调用,内嵌函数由一些特定的指令组成,配合DSP芯片的硬件函数功能单元,能高效地完成一些用C语言很难完成的复杂操作。 The intrinsic operations are not function calls (though they have the appearance of function calls), so no branching is needed.Instead, the use of intrinsic is a way to tell the compiler to issue one or more particular instructions of the C6000 instruction set. 优化的库函数 TI也将一些通用的运算模块封装成库函数,这些库函数都经过了深度的优化,能特别高效地完成相应的运算。

  • 发表了主题帖: TI C6000硬件架构优化策略

    1. 选择合适的编译选项(介绍部分) -o0/1/2/3:最重要的优化选项;如果选择了-o3,编译器将会尽可能尝试所有可行的优化手段,但有时也可能会使得优化后的程序出现错误。-o0和-o1将不会产生优化错误,但优化的性能则大大降低。 -g:允许编译器插入符号调试信息,它在开发调试阶段是非常好的工具,但在最终产品代码编译中应避免使用,因为它会减少并行处理指令,并占用额外的代码空间,极大地影响代码性能。 -mt:指示编译器,应用中所有的函数中的指针参数都不指向同一个地址,但它只作用于函数参数中的指针,对函数内部的本地指针无效。 -k和-mw:这两个选项与最终代码性能无关,但利用他们可以获得编译器的优化反馈信息,帮助编程者调整优化策略。-k选项保留编译器的汇编输出;-mw输出软件流水的相关信息 2. “restrict”关键字 restrict的作用和-mt编译选项相似,它告诉编译器某个指针不会和函数中的其它指针指向同一个内存。 the restrict keyword can be applied to any pointers, regardless of whether it is a parameter, a local variable, or an element of a referenced dataobject. Moreover, because the restrict keyword is only effective in the function it is in, it can be used whenever needed 注意:“restrict”关键字也不能随便乱加,我们需要了解C6000的片上内存组成,只有当两个指针所指的内存在不同的block里时,restrict才是合法的。 3. 通过编译指示(pragma)提供信息 可以在代码中插入一些特定语法的编译指示指令,来告知编译器有关代码的一些信息。因为编译器在缺少信息的情况下,总是以最坏的打算来优化代码,如果编程者能提供一些关键信息,会大大帮助编译器做出好的决策。最常用的有MUST_ITERATE和UNROLL两种。 MUST_ITERATE:提供关于循环次数的一些确切信息:最小可能循环次数、最大可能循环次数以及循环次数为某个factor的倍数。它的使用语法如下: 当不能确定某些参数时,允许对其缺省: UNROLL:展开指示告诉编译器可以对循环代码进行适当的展开,其使用语法如下: 在展开指示之前,也最好用MUST_ITERATE指令告诉编译器循环次数为展开系数的倍数,这样可以避免产生额外的代码来处理异常情况,如: 展开的好处有两点:一是使得编译器可以更加均衡地利用各运算单元;二是编译器有更多的机会使用SIMD指令。但有一点需要注意的是:展开将会使得循环体增大。 4. 循环体优化的注意事项 循环的优化关键在于使得循环能够被编排成软件流水。 For complex loops, such as nested loops, conditional branches inside loops, and function calls inside loops, the effectiveness of the compiler may be compromised. When the situation becomes too complex, the compiler might not be able to pipeline at all. 编译器仅对内部循环执行软件流水。 软件流水循环可包含instrinsics,但不能包含函数调用。 循环结构中不可有break和goto语句,不可有条件中止,使循环提前退出的指令。 条件代码应尽量简单,在C64XX中,条件代码需要超过6个寄存器时,循环不可进行软件流水。 避免循环体内容过于复杂,造成寄存器组不够用。 如果要求一个寄存器的生命太长,这个代码不能进行软件流水。 循环结构中不要包含改变循环计数器数值的代码。

TA暂时无记录哦~

最近访客

< 1/4 >

统计信息

已有369人来访过

  • 芯币:4042
  • 好友:--
  • 主题:816
  • 回复:81
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言