Jacktang

  • 2019-06-19
  • 发表了主题帖: MSP432 MCU发挥实时操作系统所具有的优势

    用32位ARM系统进行开发时通常需要立即应对多个操作—在这种情况下,实时操作系统 (RTOS) 会派得上用场。 MSP432 MCU提供与数个TI RTOS解决方案(其中包括TI-RTOS和ENergia MT)和第三方RTOS解决方案(其中包括FreeRTOS,ARM CMSIS-RIX和Micrium-OS)的兼容性。  由于无需从头开始创建基本系统软件函数,RTOS的使用可以加快开发进度,并且可以在更加复杂的嵌入式系统中更好地管理数个资源!   对于只使用内核的准系统选项,在开始时只使用4kB的代码,你可以使用许多出色功能,诸如多任务、软件中断、软件定时器、甚至是针对低功耗模式进行优化的动态时钟运行。对于那些需要功能更强大的RTOS来说,TI-RTOS(ARM RTX可能也可以实现)还提供了很多稳健耐用的驱动程序,这些驱动程序可以帮助你即时高效控制不同外设或通信层,比如说Wi-Fi,TCP-IP,或者串行通信。这些RTOS中的一些还是专门被编写用来充分利用每个MSP432 MCU所特有的超低功耗特性。比如说,TI-RTOS具有一个独特电源管理模块,可以根据你的性能需要来配置整个系统,用单个简单的API取代了一行又一行代码。 通过提供预先测试和预集成的必要系统软件组件,RTOS使得开发人员能够立即将注意力转向使他们的应用区别于其它产品方面。 在这个即将推出的RTOS博客系列中,我们将着重介绍那些能够与全新MSP432 MCU一同使用的不同RTOS解决方案。今天,我们先从TI-RTOS入手。在这个系列的下一篇博客中,我们将讨论: -          与MSP32 MCU一同使用Real-Time Engineers Ltd(实时工程师公司)出品的FreeRTOS(6月1日) -          与MSP432 MCU一同使用Keil生产的ARM CMSIS-RTX(6月9日) TI-RTOS由TI开发和维护,MSP432 MCU提供超过50个示例来实现对TI-RTOS的完全支持!下面是TI-RTOS的主要结构: 对于增加的节电功能,使用Power Manager(电源管理器)来简化和优化运行期间的功率。相对于其它RTOS解决方案,这是TI-RTOS所具有的独特特性。 为了简化软件开发,TI-RTOS还包括可以与TI-RTOS内核,甚至其它RTOS解决方案一同工作的功率监控驱动程序。下面是TI-RTOS所支持的驱动程序列表。 此外,对于那些Energia的忠实拥趸—TI-RTOS提供针对Energia MT的底层结构,这是第一款为业余爱好者准备的支持多线程IDE的MSP432 MCU!

  • 发表了主题帖: 错误empty character constant的解决办法

          用gcc编译如上程序时出现了“empty character constant”的错误。 原因在于第26行中单引号要有个空格,empty character constant这个英文的意思就是提示空字符。

  • 发表了主题帖: keil错误和警告

    keil 是使用比较广泛的单片机开发环境,在使用的过程中,工程编译完毕后可能会出现错误或者警告。对于错误必须要改,但是对于警告而言,你可以忽略。但值得一提的是,搞技术的人多多少少都有点强迫症,如果把警告在那里放着,你看着肯定不舒服,对于经常出现的警告和错误我大体总结了一下,希望对大家能有所帮助。 1. Warning 280:’i’:unreferenced local variable 说明 局部变量 i 在函数中未作任何的存取操作; 解决方法 消除函数中 i变量的声明; 2 Warning 206:’LED_Init’:missing function-prototype 说明 LED_Init( )函数未作声明 或未作外部声明,所以无法给其他函数调用; 解决方法 将叙述LED_Init (void)写在程序的最前端声明,如果是其他文件的函数则要写成 extern void LED_Init (void),即作外部声明; 3 Compling :C:\8051\MANN.C Error:318:can’t open file ‘led.h’ 说明 在编译 C:\8051\MANN.C 程序过程中 由于 main.c 用了指令#include “led.h”,但却找不该文件; 解决方法 编写一个led.h 的包含档并存入到 c:\8051 的工作目录中; 4 Compling:C:\8051\LED.C Error 237:’Led_ON’:function already has a body 说明 Led_ON( )函数名称重复定义 即有两个以上一样的函数名称; 解决方法 修正其中的一个函数名称 使得函数名称都是独立的; 5 ***WARNING 16:UNCALLED SEGMENT,IGNORED FOR OVERLAY PROCESS SEGMENT: ?PR?_DELAYX1MS?DELAY 说明 DelayX1ms( )函数未被其它函数调用 也会占用程序记忆体空间; 解决方法 去掉 DelayX1ms( )函数 或利用条件编译#if …..#endif,可保留该函数并不编译; 6 ***WARNING 6 :XDATA SPACE MEMORY OVERLAP FROM : 0025H TO: 0025H 说明 外部资料ROM 的 0025H重复定义地址; 解决方法 外部资料 ROM的定义如下; Pdata unsigned char XFR_ADC _at_0x25 其中 XFR_ADC 变量的名称为0x25,请检查是否有其它的变量名称也是定义在0x25 处并修正它; 7 WARNING 206:’DelayX1ms’: missing function-prototype C:\8051\INPUT.C Error 267:’DelayX1ms‘:requires ANSI-style prototype C:\8051\INPUT.C 说明 程序中有调用DelayX1ms 函数 但该函数没定义 即未编写程序内容或函数已定义但未作声明; 解决方法 编写 DelayX1ms 的内容 编写完后也要作声明或作外部声明可在 delay.h的包含档宣告成外部 以便其它函数调用; 8 ***WARNING 1:UNRESOLVED EXTERNAL SYMBOL SYMBOL:MUSIC3 MODULE:C:\8051\MUSIC.OBJ(MUSIC) ***WARNING 2:REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL:MUSIC3 MODULE:C:\8051\MUSIC.OBJ(MUSIC) ADDRESS:0018H 说明 程序中有调用 MUSIC3函数,但未包含该函数的.c加入到工程中; 解决方法:将包含MUSIC3函数的MUSIC.c文件添加到工程文件中去; 9 ***ERROR 107:ADDESS SPACE OVERFLOW SPACE: DATA SEGMENT: _DATA_GOUP_ LENGTH: 0018H ***ERROR 118: REFERENCE MADE TO ERRONEOUS EXTERNAL SYMBOL: VOLUME MODULE: C:\8051\OSDM.OBJ(OSDM) ADDRESS: 4036H 说明 data 存储空间的地址范围为 0~0x7f,当公用变量数目和函数里的局部变量 如果存储模式设为SMALL 则局部变量先使用工作寄存器R2~R7作暂存 当存储器不够用时则会以 data型别的空间作暂存的个数超过 0x7f 时就会出现地址不够的现象; 解决方法:将data型的公共变量修改为idata型; 10 “*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL” *** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL 如果你在用C51编译器出现上面的警告,这个只是初学者和粗心者才会犯的错误:没把C文件添加到项目中! 另外,还有可能是因为存在没有被调用的已经定义的函数,或者相关的已经定义的变量没有使用。

  • 2019-06-18
  • 发表了主题帖: C2000 MCU 的 EnDat 2.2 绝对编码器主接口参考设计

         TIDM-1008是一款适用于 C2000 MCU 的 EnDat 2.2 绝对编码器主接口参考设计。C2000 位置管理器技术可提供集式解决方案来连接数字绝对编码器以及旋转变压器和 SINCOS 传感器,从而无需使用工业逆变器和伺服驱动器中常用的附加电路。TIDA-1008 所示的位置管理器 BoosterPack 是一个用于评估各种编码器接口的灵活的低电压平台,旨在与支持位置管理器的 LaunchPad(如 LAUNCHXL-F28379D)配合使用。 描述 C2000 位置管理器技术可提供集式解决方案来连接数字绝对编码器以及旋转变压器和 SINCOS 传感器,从而无需使用工业逆变器和伺服驱动器中常用的附加电路。TIDA-1008 所示的位置管理器 BoosterPack 是一个用于评估各种编码器接口的灵活的低电压平台,旨在与支持位置管理器的 LaunchPad(如 LAUNCHXL-F28379D)配合使用。随 TIDA-1008 提供的高度优化且易于使用的库和示例软件支持 EnDat 2.2 和 EnDat 2.1 标准。 特性 灵活的低电压设计支持多种绝对编码器接口以及旋转变压器和 SINCOS 传感器 TIDA-1008 与支持 C2000 位置管理器的 MCU(通过 LaunchPad)配合使用,以实现集成式 EnDat2.2 和 EnDat 2.1 数字协议解决方案 可通过软件驱动程序函数和数据结构轻松执行连接 EnDat2.2 的命令 C28x 优化 CRC 算法和数据解压缩 支持高达 8MHz 的 EnDat 时钟。经验证,适用的电缆长度最大为 100m TIDM-1008 包含一个评估板和一个展示 EnDat22 软件库的软件示例 设计指南 快速获得已通过验证的测试和仿真数据 下载设计指南 下载设计文件 TMS320F2837xD 双核 Delfino™ 微控制器 数据表 (Rev. K)  适用于C2000™ MCU 的EnDat 2.2 绝对编码器主接口参考设 计 (Rev. A) PDF 13322 2018年 6月 13日 下载英文版本 (Rev.A)  适用于C2000™ MCU 的EnDat 2.2 绝对编码器主接口参考设 计 PDF 13305 2017年 9月 26日 下载最新的英文版本 (Rev.A)  C2000 Position Manager EnDat22 Library Module User's Guide PDF 1101 2015年 11月 5日

  • 2019-06-17
  • 发表了主题帖: 如何降低微处理器中PWM DAC的纹波

          降低PWM DAC纹波的方法通常有两种:一种是降低低通滤波器的截止频率,另一种是提高PWM信号的频率。然而,前一种方法会加长上升时间,后一种方法会导致分辨率降低。本设计实例讨论了在不使用上述两种方法的情况下,如何降低PWM DAC的纹波。   我们大多数人都知道PWM DAC(数模转换器)。它们很容易实现,也很便宜,非常适合一些低性能的应用。   实现它们的方法是滤除PWM信号中的高频分量,只留下正比于占空比的低频或直流分量。但是低通滤波器并不能完全滤除PWM频率,因此低频/直流信号中通常都会有一定程度的纹波。   减少PWM DAC纹波的方法一般有两种。一种是降低低通滤波器的截止频率,另一种是提高PWM信号的频率。然而不可避免的是,更低的截止频率会延长上升时间;如果是在给定时钟频率点通过减小计数器尺寸实现的,那么更快的PWM频率会降低分辨率。   下面要讨论的设计实例非常有趣,着重介绍了另外一种降低PWM DAC纹波的方法。   事实上,我们可以使用相位差为180°的两个PWM信号来降低上述纹波。从直觉上,当两个相同频率的正弦波的相位相差180°时,它们会相互抵消,因此我们使用相位差为180°的两个PWM信号也能将彼此的谐波分量抵消干净,是这样吗?确实是这样,但并不是PWM信号的所有谐波分量都能抵消,有些分量可以抵消,有些却抵消不了。这与傅里叶级数有关,比较复杂,这里就不罗列一大堆数学公式来进行解释了。   两个PWM信号之间180°的相位差是如何实现的呢?我使用了TI的MSP320FR5969 LaunchPad,这种方法很常用。为了实现相位移动,需要两个定时器。其中一个定时器必须包含两个比较-捕获-PWM(CCP)模块,另一个只需要一个CCP模块。   在包含两个CCP模块的定时器中,可以用一个CCP模块来设置该定时器的PWM频率和占空比,另一个CCP模块产生中断,用于启动另一个定时器,两者的延时等于PWM周期的一半。另一个定时器中的CCP模块用于设置相同的PWM频率和占空比。你还必须对这个延时进行“微调”,因为软件会在PWM信号之间增加额外的时间。举例来说,在我的代码的102行,我将比较寄存器的值从(timer_period+1)/2改为了(timer_period+1)/2-27。   我做了一些小调查,想看看其它微控制器是否具有相同的硬件和能力来实现我所用的方法:许多Atmel微控制器都有1个以上的定时器,每种控制器通常都有两个CCP(比如ATmega 328),因此实现这种方法应该是可能的。另外一个常见的例子是STM32F051R8(这是一些流行的ST电路板使用的微控制器),它有11个定时器,其中许多定时器都有1个以上的CCP。TI基于ARM的微控制器通常有独立的PWM和定时器模块(如TM4C123GH6PM),因此应该更容易实现相移。使用其中一个定时器,两个PWM模块就可以以一半PWM周期的延时开启。   图1:单路和双路PWM电路。   在相移DAC的Vout端,两个PWM信号被累加在一起,结果有些谐波分量彼此抵消,最终实现了降低纹波的效果。   我们看看使用三种不同电阻值时的情况。每个PWM信号都是占空比为25%、频率为100kHz。   图2:上面的波形是传统PWM,下面的波形是双路相移PWM。从左到右每格的电压递减100mV、50mV、4mV。   从图中的结果可以看出:首先,峰-峰纹波降低了;其次,传统PWM DAC的纹波基频等于 PWM信号的频率(100kHz)。相移PWM DAC的纹波基频等于PWM信号的二次谐波(200kHz),这意味着我们用相移DAC成功地删除了PWM信号的一次谐波。   这种方法的一个优点是不用增加上升时间也能降低纹波(或者相同的纹波只需一半的上升时间)。   另外一个潜在优点是,将两个PWM设置为相隔一个计数值可以获得中间值,进而实现DAC有效分辨率的翻倍。虽然这会导致少许的不对称并增加纹波,但是影响很小可以忽略不计。

  • 发表了主题帖: 从数字PWM信号获得准确、快速稳定的模拟电压

          脉宽调制 (PWM) 是从微控制器或 FPGA 等数字器件产生模拟电压的一种常用方法。大多数微控制器都具有内置的专用 PWM 产生外设,而且其仅需几行 RTL 代码即可从 FPGA 产生一个 PWM 信号。如果模拟信号的性能要求不是太严格,那么这就是一种简单和实用的方法,因为它只需要一个输出引脚,而且与具有一个SPI 或 I2C 接口的数模转换器 (DAC) 相比,其代码开销是非常低。图 1 示出了一款典型应用,其采用一个经滤波的数字输出引脚来产生一个模拟电压。      图 1:PWM 至模拟转换   该方案的诸多不足之处您不必深究就能发现。理想情况下,一个 12 位模拟信号应具有小于 1LSB 的纹波,因而对于一个 5kHz PWM 信号需要采用一个 1.2Hz 低通滤波器。电压输出的阻抗由滤波器电阻决定,如果要保持一个大小合理的滤波电容器,那么它就会相当大。因此,输出必须只驱动一个高阻抗负载。PWM 至模拟转换函数的斜率 (增益) 由微控制器 (很可能是不准确) 的数字电源电压来决定。一个更微妙的影响是:为了保持线性度,在高态中连接至电源之数字输出引脚的有效电阻,以及在低态中连接至地的电阻,相比于滤波器电阻的阻值时, 失配必须很小。最后,PWM信号必须是连续的,旨在把输出电压保持在一个恒定值,假如处理器被置于一种低功率停机状态,这或许会产生问题。 PWM至模拟转换得到改善吗? 图 2 显示了试图弥补这些不足的方法。一个输出缓冲器允许在使用高阻抗滤波器电阻的同时提供一个低阻抗模拟输出。通过采用一个外部 CMOS 缓冲器改善了增益准确度,该缓冲器由一个高精度基准来供电,这样 PWM 信号摆幅在地电位和一个准确的高电平之间。此电路是有用的,但缺点是组件数量多,且无法改善 1.1 秒的稳定时间,再者也没有办法在不使用连续PWM 信号的情况下“保持” 模拟值。     图 2:PWM 至模拟转换得到改善吗?   下一页:改善PWM 至模拟转换改善了 PWM 至模拟转换! LTC2644 和 LTC2645 是具有内部 10ppm/°C 基准的双通道和四通道 PWM 至电压输出 DAC,可从数字PWM 信号提供真正的 8 位、10 位或 12 位性能。LTC2644 和 LTC2645 克服了上面提到的那些问题,采取的方法是直接测量输入 PWM 信号的占空比,并在每个上升沿上将适当的 8、10 或 12 位代码发送至一个高精度 DAC。 一个内部 1.25V 基准把全标度输出设定为 2.5V,如果需要一个不同的全标度输出,则可使用一个外部基准。一个单独的 IOVCC 引脚负责设定数字输入电平,从而允许直接连接至 1.8V FPGA、5V 微控制器或介于其间的任何电压。DC 准确度指标是非常出色的,具有 5mV 偏移、0.8% 最大增益误差和 2.5LSB (12 位) 最大 INL。输出稳定时间为 8μs,即可从 PWM 输入的上升沿稳定到终值 (在 12 位时为 1LSB) 的 0.024% 之内。对于 12 位版本,PWM 频率范围为 30Hz 至 6.25kHz。   图 3:4 通道 PWM 至模拟转换   (点击查看大图)   多用途的输出模式 图 4 示出了一款典型的电源修整 / 裕度调节应用电路,其利用了 LTC2644 的另一项独特特性。把 IDLSEL 连接至高电平将选择“采样 / 保持”操作;输出在启动时为高阻抗 (无裕度调节),输入端上的一个连续高电平将导致输出无限期地保持其数值,而一个连续低电平则把输出置于高阻抗状态。因此,在上电时可利用一个 PWM 突发脉冲 (其后随一个高电平) 对电源进行一次修整。将 PWM 信号拉至低电平可使电路干净地退出裕度调节操作。把 IDLSEL 连接至 GND 将选择“透明模式”,在该模式中,输入端上的一个连续高电平把输出设定至全标度,而一个连续低电平则把输出设定至零标度。     图 4:裕度调节应用电路   结论 倘若遭遇典型 PWM 至模拟转换方法的局限性,请不要绝望。LTC2645 可从脉宽调制数字输出产生准确、快速稳定的模拟信号,同时保持了低组件数目和代码简单性。

  • 发表了主题帖: msp430单片机程序升级的方法有哪些

         在搞430的FLASH的自定义法(利用串口)程序烧写,烧写完成后断电复位,reset按键就可以运行新的程序。但是和学长交流了一下,这种方法不够好,希望有一种软复位的方式。于是百度了一下,都是些对看门狗进行写入特殊值使得430的cpu复位。反正个人是没有采用。      因为在搞程序的烧写下载,所以看了一下430的BSL。看到里面有一段话,关于从C代码中启动BSL的方法。如下:   从一个外部应用中启动BSL   将程序计数器设定到内存为位置0x1000 来启动BSL。堆栈一直被复位,而RAM 被清空。应该注意的是,GIE 位未被禁用,所以如果不需要中断的话,这一步应该通过调用应用来完成,并且如果它们被使用的话,这一步应该从“返回BSL”返回。   由于堆栈被复位,位置0x1000 也可以被作为一个C 功能进行调用,示例代码如下:   ((void (*)())0x1000)()   于是想到,既然可以从C里面跳转到0x1000,那么也可以跳转到其他地址,比如复位地址了。   以6638为例。430的复位中断矢量地址是0xFFFE,里面存储了将要跳转的物理地址。6638的代码区起始地址是0x8000,正常复位是先进入复位中断,然后PC指针导入地址0x8000,然后从0x8000开始执行代码。那么软复位则是,执行((void (*)())0x8000)(),直接PC指针被导入0x8000的地址,而这个地址正好是6638的代码区起始地址,于是软复位了。个人分析一下这个指令,如有错误敬请大神们指正。   从代码上讲,(void (*)()是一个指向空函数的指针,((void (*)())0x8000)()是将0x8000强制转换为函数指针后进行函数调用,于是0x8000便被送入了PC指针。   对于其他的430单片,去查其数据手册FLASH段,弄清其代码区的开始地址,也可以用这个方法软复位了。   实测,IAR,CCS下编译、实践通过。

  • 发表了主题帖: 关于单片机的字库设计

    当需要液晶显示的时候,汉字的显示一直不是那么方便(在没有*字库的情况下)。 如果纯粹取模的话,就要考虑自作一个字库需要花费的时间和占用的flash资源。对于UCOS来说,就像楼主使用的破开发板,只有256Kflash,一个16*16 GB点阵字库就要占用200K+,自然是不可能放入用户源码的。 于是乎,楼主开始使用*字库,关于*字库碰到的一些问题在这里给大家简单说说,有用的话的就给楼主赞一个,哈哈哈 1.关于GB2312,可百度。 2.字库一般选用flash器件,采用SPI协议通信,通常4兆的片子足够使用常用字库的存储。 3.自制字库,最后会放上楼主曾用过的资源。纤细过程(加一些格式,好看得清楚,哈哈哈): 第一步,当然需要你将你所用的SPIflasn的初始化以及读写函数写好(我使用W25X16,2M,传输速率最大74MHZ,很快的;写函数:void W25X_Write_Bytes(uint32_t addr,u8* pBuffer, u16 nBytes) 注:W25X16写时,需要先擦除。读函数:void W25X_Read_Bytes(uint32_t addr, u8* pBuffer, u16 nBytes) 第二步,编写串口传输函数,采用串口中断的方式,波特率设置为115200(测试没有问题),接收外部输入的一个字节后立马将其写入SPI FLASH。与之前两个字符表示一个字节的方法速度提升一倍。 代码: view plaincopy to clipboardprint? u8 result;      u32 pAddr=0;      void USART1_IRQHandler(void)      {      if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)       {      result = USART_ReceiveData(USART1);       W25X_Write_Bytes(pAddr++,&result,1);      USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除串口接受中断      }      }   第三步,设置一个按键进行擦除操作,通过串口或者LCD进行交互,以提示是否擦除完成。可以进行写FLASH。 第四步,制作中文字库,GB3212库包含6768个简体中文,首先打开“取点阵.exe”软件,然后在软件中打开“字符库.txt”文件。然后选择取模方式,可以设置字体样式、大小和方向设置等。注意“方向设置“选项,这里为了对应工程中的显示程序,选择——横向取模,高位在坐。其它选项只要适当修改显示程序就可以。然后点击“输出“按钮,将在该目录下得到字模数组文件(temp.txt)。 第五步,整理字库文件。上一步得到的字模数组文件还不能直接使用,需要进行整理以适合串口发送,去除各种注释符和标点字符,只保留两位字符组成的十六进制格式。接着将“temp.txt”改名为“HzLib.txt”,然后运行“整理字库.exe”,此时将得到整理好的字库“OutHzLib.txt”然后就可以直接将该字库通过串口发送到MCU了。 第六步,串口发送数据。推荐用附件中的串口调试软件,因为有些软件在对于文件发送这个功能做得似乎有些问题。本人也测试了两款串口调试软件,均不能得到结果,如果有其它好的也可以,反正只要达到目的就行。设置串口参数,然后在发送区设置中勾选“按十六进制发送”,点击“启动文件数据原”选项,选择制作好的字库“OutHzLib.txt”,不要点击“文件载入”。 第七步,打开串口,将板子接通电源,首先对Flash进行擦除操作,提示擦除结束后,点击串口发送,然后就慢慢等着字库写入FLASH。测试在波特率为115200下,取模大小为16*16,耗时为70s,似乎也不太久,如果取模越大,耗时就越长。写好字模后,就可以在工程中调用字库进行中文显示了(取GBK内码操作见工程)。另外如果flash容量够大的话,还可以写入其它字体样式和大小的字库,做一个专属的字库芯片。 4.X宝一个片子,经济实惠,随拿随用。做好了字库,就剩下怎样使用了 另外, 1.建议使用总线型SPI,速率绝对有保障。具体代码看各自的板子了。 2.如果使用软件SPI,送一段: view plaincopy to clipboardprint? #define MOSI_H GPIO_SetBits(GPIOA, GPIO_Pin_5)    #define MOSI_L GPIO_ResetBits(GPIOA, GPIO_Pin_5)    #define SCLK_H GPIO_SetBits(GPIOA, GPIO_Pin_7)    #define SCLK_L GPIO_ResetBits(GPIOA, GPIO_Pin_7)    #define MISO_H GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)     void spi_init(void)    {     CE_25_1;   MOSI_H;    MISO_H;   SCLK_H;    }     unsigned char SPI_SendByte(unsigned char dt)    {    u8 i;     u8 temp=0;       for(i=8;i>0;i--)       {         if(dt&0x80)MOSI_H;            else MOSI_L;      SCLK_L;        SCLK_H;            temp<<=1;        dt<<=1;         if(MISO_H) temp++;              }     return temp;    }    

  • 发表了主题帖: 汽车类电阻式桥接压力传感器接口参考设计

    本帖最后由 Jacktang 于 2019-6-17 12:01 编辑        跟笔尖一样大小!!!TIDA-00793是汽车类电阻式桥接压力传感器接口参考设计,此参考设计使用 PGA301-Q1 为电阻桥型压力传感器提供简单、可靠且精确的传感器信号调节解决方案。该设计中实现的保护策略可防止压力传感器受到线束故障、EMI 和汽车电气瞬变的影响。设计指南中系统介绍了该设计中涉及的理论、操作和挑战。想要了解更多, 特性 0.17% 的温度精度(-40°C 至 125°C) 二阶温度和线性补偿算法 23x23mm 的外形设计 针对线束故障的保护(过压和反极性保护)、断线检测 符合 ISO7637-3 瞬态脉冲要求并经过测试符合 ISO11452-4 大电流注入 (BCI) 要求 原理图  

  • 发表了主题帖: RFID系统常用的防碰撞算法

    1.纯ALOHA算法:主要采用标签先发言的方式,即电子标签一旦进入阅读器的工作范围获得能量后,便向阅读器主动发送自身的序列号。在某个电子标签向阅读器发送数据的过程中,如果有其它电子标签也同时向该阅读器发送数据,此时阅读器接收到的信号就会产生重叠,导致阅读器无法正确识别和读取数据。阅读器通过检测并判断接收到的信号是否发生碰撞,一旦发生碰撞,阅读器则向标签发送指令使电子标签停止数据的传送,电子标签接到阅读器的指令后,便随机的延迟一段时间再重新发送数据。在纯ALOHA算法中,假设电子标签在t时刻向阅读器发送数据,与阅读器的通信时间为To,则碰撞时间为2T0。G为数据包交换量,S为吞吐率 (G=0.5时最大S=18.4%)  2.时隙ALOHA算法:为提高RFID系统的吞吐率,可以把时间划分为多段等长的时隙,时隙的长度由系统时钟确定,并且规定电子标签只能在每个时隙的开始时才能向阅读器发送数据帧,这就是时隙ALOHA算法;根据上述规定可得,数据帧要么成功发送,要么完全碰撞,避免了纯ALOHA算法中部分碰撞的发生,使碰撞周期变为To;(G=1时最大S=36.8%)  3.动态时隙ALOHA算法:首先由阅读器把帧长度 N 发送给电子标签,电子标签则产生[1,N]之间的随机数,接下来各电子标签选择相应的时隙,与阅读器进行通信;如果当前时隙与电子标签随机产生的数相同,电子标签则响应阅读器的命令,若不同,标签则继续等待。假如当前时隙内仅有一个电子标签响应,阅读器就读取该标签发送的数据,读取完了以后就使该标签处于“无声”状态。如果当前时隙内有多个标签响应,则该时隙内的数据就出现了碰撞,此时阅读器会通知该时隙内的标签,让它们在下一轮帧循环中重新产生随机数参与通信。逐帧循环,直到识别出所有电子标签为止。  4.二进制搜索算法:多个标签进入读写器工作场后,读写器发送带限制条件的询问命令,满足限制条件的标签回答,如果发生碰撞,则根据发生错误的位修改限制条件,再一次发送询问命令,直到找到一个正确的回答,并完成对该标签的读写操作。对剩余的标签重复以上操作,直到完成对所有标签的读写操作。 

  • 发表了主题帖: RFID射频识别

    1、MFRC522是高度集成的非接触式(13.56MHz)读写卡芯片。此发送模块利用调制和解调的原理,并将它们完全集成到各种非接触式通信方法和协议中。MFRC522的内部发送器部分可驱动读写器天线与ISO14443A/MIFARE卡和应答机的通信,无需其它的电路。接收器部分提供一个功能强大和高效的解调和译码电路,用来处理兼容ISO14443A/MIFARE卡和应答机的信号。 2、RC522支持SPI、I2C和UART接口,本实验使用的是SPI接口。RC522的SPI总线接口有其自身的时序要求。它只能工作于从模式,最高传输速率为10 Mbps,数据与时钟相位关系满足“空闲态时钟为低电平,在时钟上升沿同步接收和发送数据,在下降沿数据转换”的约束关系。简化MRFC522框图:  模拟接口用来处理模拟信号的调制和解调。非接触式UART用来处理与主机通信时的协议要求。FIFO缓冲区快速而方便地实现了主机和非接触式UART之间数据传输。 3、IC卡特点: 容量为8K位EEPROM 分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位 每个扇区有独立的一组密码及访问控制 每张卡有唯一序列号,为32位 具有防冲突机制,支持多卡操作 无电源,自带天线,内含加密控制逻辑和通讯逻辑电路 数据保存期为10年,可改写10万次,读无限次 工作温度:-20℃~50℃(湿度为90%) 工作频率:13.56MHZ 通信速率:106 KBPS 读写距离:10 cm以内(与读写器有关) 卡片的电气部分只由一个天线和ASIC组成。 天线:卡片的天线是只有几组绕线的线圈,很适于封装到IS0卡片中。 ASIC:卡片的ASIC由一个高速(106KB波特率)的RF接口,一个控制单元和一个 8K位EEPROM组成。 工作原理:读写器向M1卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。 4、M1射频卡与MFRC522的通讯: 5、 复位应答: M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。 防冲突机制: 当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。 选择卡片: 选择被选中的卡的序列号,并同时返回卡的容量代码。 三次互相确认: 选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。) 读数据块的操作: 读(Read):读一个块; 写(Write):写一个块; 加(Increment):对数值块进行加值; 减(Decrement):对数值块进行减值; 存储(Restore):将块中的内容存到数据寄存器中; 传输(Transfer):将数据寄存器中的内容写入块中; 中止(Halt):将卡置于暂停工作状态; 6、 RFID.c #include "RFID.h" #include "delay.h" #include "SPI.h" /***************************************** *功    能:读RC522寄存器 *参数说明:Address[IN]:寄存器地址 *返    回:读出的值 ******************************************/ uint8_t ReadRawRC(uint8_t   Addr) {     uint16_t ReData = 0;     uint16_t TempAddr = 0; //    uint8_t i = 0;          SPI_CS_Status(LOW);              delay_us(10);                                                                                      TempAddr = ((Addr << 1) | 0x80) & 0xfe ;                                                                                                                SPI_Send_Data(TempAddr);     ReData = SPI_Get_Data();          delay_us(10);     SPI_CS_Status(HIGH);     delay_us(10);     return    ReData; } /**************************************** *功    能:写RC522寄存器 *参数说明:Address[IN]:寄存器地址 *          value[IN]:写入的值 *****************************************/ void WriteRawRC(uint8_t   Addr, uint8_t  Data) {       uint8_t TempAddr = 0;     SPI_CS_Status(LOW);         delay_us(10);                                                                                                                                                                                     TempAddr = ((Addr << 1) & 0x7e);                                                  SPI_Send_Data(TempAddr);     SPI_Send_Data(Data);          delay_us(10);     SPI_CS_Status(HIGH);     delay_us(10); } /*对RCC522芯片进行复位*/ int8_t PcdReset(void) {     delay_us(1);     WriteRawRC(CommandReg,PCD_RESETPHASE);         WriteRawRC(CommandReg,PCD_RESETPHASE);     delay_us(3000);          WriteRawRC(ModeReg,0x3D);                WriteRawRC(TReloadRegL,30);                WriteRawRC(TReloadRegH,0);     WriteRawRC(TModeReg,0x8D);     WriteRawRC(TPrescalerReg,0x3E);              WriteRawRC(TxASKReg,0x40);//±?D?òa         return MI_OK; } /*打开天线*/ void PcdAntennaOn(void) {     uint8_t   i;     i = ReadRawRC(TxControlReg);     if (!(i & 0x03))     {         SetBitMask(TxControlReg, 0x03);     } } /*关闭天线*/ void PcdAntennaOff(void) {     ClearBitMask(TxControlReg, 0x03); } /*针对ISO14443A型卡进行初始化*/ int8_t M500PcdConfigISOType(uint8_t   type) {     if (type == 'A')                        {          ClearBitMask(Status2Reg,0x08);         WriteRawRC(ModeReg,0x3D);         WriteRawRC(RxSelReg,0x86);         WriteRawRC(RFCfgReg,0x7F);            WriteRawRC(TReloadRegL,30);         WriteRawRC(TReloadRegH,0);         WriteRawRC(TModeReg,0x8D);         WriteRawRC(TPrescalerReg,0x3E);         delay_us(1000);         PcdAntennaOn();   }   else{ return 1; }        return MI_OK; } /*初始化RC522*/ void InitRc522(void) {   Rc522_spi_lowlevel_init();    /*SPI初始化*/   PcdReset();                                    /*对RC522芯片进行复位*/   PcdAntennaOff();                      /*关闭天线*/   PcdAntennaOn();                            /*打开天线*/   M500PcdConfigISOType( 'A' );/*针对ISO14443A型卡进行初始化*/ } /************************************ *功    能:置RC522寄存器位 *参数说明:reg[IN]:寄存器地址 *          mask[IN]:置位值 *************************************/ void SetBitMask(uint8_t   reg,uint8_t   mask)   {     int8_t   tmp = 0x0;     tmp = ReadRawRC(reg);     WriteRawRC(reg,tmp | mask);   } /*********************************** *功    能:清RC522寄存器位 *参数说明:reg[IN]:寄存器地址 *          mask[IN]:清位值 ************************************/ void ClearBitMask(uint8_t   reg,uint8_t   mask)  {     int8_t   tmp = 0x0;     tmp = ReadRawRC(reg);     WriteRawRC(reg, tmp & ~mask);  // clear bit mask }  /*********************************************** *功    能:通过RC522和ISO14443卡通讯 *参数说明:Command[IN]:RC522命令字 *          pInData[IN]:通过RC522发送到卡片的数据 *          InLenByte[IN]:发送数据的字节长度 *          pOutData[OUT]:接收到的卡片返回数据 *          *pOutLenBit[OUT]:返回数据的位长度 ************************************************/ int8_t PcdComMF522(uint8_t   Command,                   uint8_t *pIn ,                   uint8_t   InLenByte,                  uint8_t *pOut ,                   uint32_t *pOutLenBit) {     int8_t   status = MI_ERR;     uint8_t   irqEn   = 0x00;     uint8_t   waitFor = 0x00;     uint8_t   lastBits;     uint8_t   n;     uint32_t   i;     switch (Command)     {         case PCD_AUTHENT:             irqEn   = 0x12;             waitFor = 0x10;             break;         case PCD_TRANSCEIVE:             irqEn   = 0x77;             waitFor = 0x30;             break;         default:             break;     }         WriteRawRC(ComIEnReg,irqEn|0x80);     ClearBitMask(ComIrqReg,0x80);         WriteRawRC(CommandReg,PCD_IDLE);     SetBitMask(FIFOLevelReg,0x80);                   for (i=0; i<InLenByte; i++)     {   WriteRawRC(FIFODataReg, pIn );    }     WriteRawRC(CommandReg, Command);       //        n = ReadRawRC(CommandReg);          if (Command == PCD_TRANSCEIVE)     {    SetBitMask(BitFramingReg,0x80);  }                                                            i = 500;     do      {         n = ReadRawRC(ComIrqReg);         i--;     }     while ((i!=0) && !(n&0x01) && !(n&waitFor));     ClearBitMask(BitFramingReg,0x80);     if (i!=0)     {             if(!(ReadRawRC(ErrorReg)&0x1B))         {             status = MI_OK;             if (n & irqEn & 0x01)             {   status = MI_NOTAGERR;   }             if (Command == PCD_TRANSCEIVE)             {                    n = ReadRawRC(FIFOLevelReg);                   lastBits = ReadRawRC(ControlReg) & 0x07;                 if (lastBits)                 {   *pOutLenBit = (n-1)*8 + lastBits;   }                 else                 {   *pOutLenBit = n*8;   }                 if (n == 0)                 {   n = 1;    }                 if (n > MAXRLEN)                 {   n = MAXRLEN;   }                 for (i=0; i<n; i++)                 {   pOut = ReadRawRC(FIFODataReg);    }             }         }         else         {   status = MI_ERR;   }              }         SetBitMask(ControlReg,0x80);               WriteRawRC(CommandReg,PCD_IDLE);      return status; } /************************************************************* *功    能:寻卡 *参数说明: req_code[IN]:寻卡方式 *                0x52 = 寻感应区内所有符合14443A标准的卡 *                0x26 = 寻未进入休眠状态的卡 *          pTagType[OUT]:卡片类型代码 *                0x4400 = Mifare_UltraLight *                0x0400 = Mifare_One(S50) *                0x0200 = Mifare_One(S70) *                0x0800 = Mifare_Pro(X) *                0x4403 = Mifare_DESFire *返    回: 成功返回MI_OK **************************************************************/ int8_t PcdRequest(uint8_t   req_code,uint8_t  *pTagType) {   char status;    unsigned int unLen;   unsigned char ucComMF522Buf[MAXRLEN];     ClearBitMask(Status2Reg,0x08);//寄存器包含接收器和发送器和数据模式检测器的状态标志   WriteRawRC(BitFramingReg,0x07);//不启动数据发送   SetBitMask(TxControlReg,0x03);//TX1、TX2输出信号将传递经发送数据调制的13.56MHz的能量载波信号。   ucComMF522Buf[0] = req_code;    //将寻卡命令填入到数组   status =PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);//通过522发送req_code命令,并接收返回数据,存到ucComMF522Buf中   if ((status == MI_OK) && (unLen== 0x10))//这个为啥是0x10,因为是2个字节共16bit   {         *pTagType     =ucComMF522Buf[0];      *(pTagType+1) =ucComMF522Buf[1];//获取卡类型   }   else   {        status = MI_ERR;     }      return status; } /************************************************************** *功    能:防冲撞 *参数说明: pSnr[OUT]:卡片序列号,4字节 *返    回: 成功返回MI_OK ***************************************************************/  int8_t PcdAnticoll(uint8_t *pSnr) {     char status;     unsigned char i,snr_check=0;     unsigned int unLen;     unsigned char ucComMF522Buf[MAXRLEN];         ClearBitMask(Status2Reg,0x08); //寄存器包含接收器和发送器和数据模式检测器的状态标志     WriteRawRC(BitFramingReg,0x00);//不启动数据发送,接收的LSB位存放在位0,接收到的第二位放在位1,定义发送的最后一个字节的位数为8     ClearBitMask(CollReg,0x80);//所有接收的位在冲突后将被清除。       ucComMF522Buf[0] = PICC_ANTICOLL1;    //0x93表明串联级别1     ucComMF522Buf[1] = 0x20;            //表明PCD发送字节数为整两个字节       status =PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);       if (status == MI_OK)          {                    for (i=0; i<4; i++)                    {                               *(pSnr+i)  = ucComMF522Buf;                             snr_check ^=ucComMF522Buf;                    }                    if (snr_check !=ucComMF522Buf)//返回四个字节,最后一个字节为校验位                    {                               status =MI_ERR;                       }     }     SetBitMask(CollReg,0x80);     return status; } /*读ID函数*/ uint32_t Rc522_read_uid(void) {     uint8_t status = 0;     uint8_t car_type[2];     uint8_t uid[4];          status=PcdRequest(0x52,car_type);     if(status==MI_OK)      {         status = PcdAnticoll(uid);       }     if(status==MI_OK)      {         return ((uid[0] << 24) | (uid[1] << 16) | (uid[2] << 8) | (uid[3]));     }     return 0; } 7、RFID.h #ifndef __BSP_RFID_H_ #define __BSP_RFID_H_ #ifdef __cplusplus  extern "C" { #endif          #include "stm32f0xx.h"         #include <string.h>          #define Rc522_spi_lowlevel_init()        SPI_Gpio_Init()     #define MAXRLEN        18     #define MIN_STRENGTH  228     #define DEF_FIFO_LENGTH             64                #define PCD_IDLE                  0x00        //取消当前命令        #define PCD_AUTHENT               0x0E        //验证密钥        #define PCD_RECEIVE               0x08        //接收数据        #define PCD_TRANSMIT              0x04        //发送数据        #define PCD_TRANSCEIVE            0x0C        //发送并接收数据        #define PCD_RESETPHASE            0x0F        //复位        #define PCD_CALCCRC               0x03        //CRC计算        #define PICC_REQIDL               0x26        //寻天线区内未进入休眠状态        #define PICC_REQALL               0x52        //寻天线区内全部卡        #define PICC_ANTICOLL1            0x93        //防冲撞        #define PICC_ANTICOLL2            0x95        //防冲撞        #define PICC_AUTHENT1A            0x60        //验证A密钥        #define PICC_AUTHENT1B            0x61        //验证B密钥        #define PICC_READ                 0x30        //读块        #define PICC_WRITE                0xA0        //写块        #define PICC_DECREMENT            0xC0        //扣款        #define PICC_INCREMENT            0xC1        //充值        #define PICC_RESTORE              0xC2        //调块数据到缓冲区        #define PICC_TRANSFER             0xB0        //保存缓冲区中数据        #define PICC_HALT                 0x50        //休眠        #define  RFU00                 0x00         #define  CommandReg            0x01    //停止和启动命令的执行     #define  ComIEnReg             0x02         #define  DivlEnReg             0x03         #define  ComIrqReg             0x04         #define  DivIrqReg             0x05     #define  ErrorReg              0x06         #define  Status1Reg            0x07         #define  Status2Reg            0x08   //包含接收器、发送器和数据模式检测器的状态位     #define  FIFODataReg           0x09     #define  FIFOLevelReg          0x0A     #define  WaterLevelReg         0x0B     #define  ControlReg            0x0C     #define  BitFramingReg         0x0D     #define  CollReg               0x0E     #define  RFU0F                 0x0F     // PAGE 1       #define  RFU10                 0x10     #define  ModeReg               0x11            //定义发送和接受的常用模式     #define  TxModeReg             0x12     #define  RxModeReg             0x13     #define  TxControlReg          0x14            //控制天线驱动器管脚Tx1和Tx2的逻辑操作     #define  TxASKReg              0x15            //保留为将来用的寄存器     #define  TxSelReg              0x16     #define  RxSelReg              0x17            //选择内部接收器设置     #define  RxThresholdReg        0x18     #define  DemodReg              0x19     #define  RFU1A                 0x1A     #define  RFU1B                 0x1B     #define  MifareReg             0x1C     #define  RFU1D                 0x1D     #define  RFU1E                 0x1E     #define  SerialSpeedReg        0x1F     // PAGE 2         #define  RFU20                 0x20       #define  CRCResultRegM         0x21     #define  CRCResultRegL         0x22     #define  RFU23                 0x23     #define  ModWidthReg           0x24     #define  RFU25                 0x25     #define  RFCfgReg              0x26        //配置接收器增益     #define  GsNReg                0x27     #define  CWGsCfgReg            0x28     #define  ModGsCfgReg           0x29     #define  TModeReg              0x2A        //定义内部定时器的设置,该寄存器分为2个8位寄存器     #define  TPrescalerReg         0x2B        //定义内部定时器的设置     #define  TReloadRegH           0x2C        //描述16位长的定时器重装值,该寄存器分为2个8位寄存器     #define  TReloadRegL           0x2D        //描述16位长的定时器重装值     #define  TCounterValueRegH     0x2E     #define  TCounterValueRegL     0x2F     // PAGE 3           #define     RFU30                 0x30     #define     TestSel1Reg           0x31     #define     TestSel2Reg           0x32     #define     TestPinEnReg          0x33     #define     TestPinValueReg       0x34     #define     TestBusReg            0x35     #define     AutoTestReg           0x36     #define     VersionReg            0x37     #define     AnalogTestReg         0x38     #define     TestDAC1Reg           0x39       #define     TestDAC2Reg           0x3A        #define     TestADCReg            0x3B        #define     RFU3C                 0x3C        #define     RFU3D                 0x3D        #define     RFU3E                 0x3E        #define     RFU3F                                  0x3F     #define MI_ERR                      0xFE      #define MI_OK                          0      #define MI_CHK_OK                      0      #define MI_CRC_ZERO                    0      #define MI_CRC_NOTZERO                 1      #define MI_NOTAGERR                 0xFF      #define MI_CHK_FAILED               0xFF      #define MI_CRCERR                   0xFE      #define MI_CHK_COMPERR              0xFE      #define MI_EMPTY                    0xFD      #define MI_AUTHERR                  0xFC      #define MI_PARITYERR                0xFB      #define MI_CODEERR                  0xFA      #define MI_SERNRERR                 0xF8      #define MI_KEYERR                   0xF7      #define MI_NOTAUTHERR               0xF6      #define MI_BITCOUNTERR              0xF5      #define MI_BYTECOUNTERR             0xF4      #define MI_IDLE                     0xF3      #define MI_TRANSERR                 0xF2      #define MI_WRITEERR                 0xF1      #define MI_INCRERR                  0xF0      #define MI_DECRERR                  0xEF      #define MI_READERR                  0xEE      #define MI_OVFLERR                  0xED      #define MI_POLLING                  0xEC      #define MI_FRAMINGERR               0xEB      #define MI_ACCESSERR                0xEA      #define MI_UNKNOWN_COMMAND          0xE9      #define MI_COLLERR                  0xE8      #define MI_RESETERR                 0xE7      #define MI_INITERR                  0xE7      #define MI_INTERFACEERR             0xE7      #define MI_ACCESSTIMEOUT            0xE5      #define MI_NOBITWISEANTICOLL        0xE4      #define MI_QUIT                     0xE2      #define MI_RECBUF_OVERFLOW          0xCF      #define MI_SENDBYTENR               0xCE      #define MI_SENDBUF_OVERFLOW         0xCC      #define MI_BAUDRATE_NOT_SUPPORTED   0xCB      #define MI_SAME_BAUDRATE_REQUIRED   0xCA      #define MI_WRONG_PARAMETER_VALUE    0xC5      #define MI_BREAK                    0x9E      #define MI_NY_IMPLEMENTED           0x9D      #define MI_NO_MFRC                  0x9C      #define MI_MFRC_NOTAUTH             0x9B      #define MI_WRONG_DES_MODE           0x9A      #define MI_HOST_AUTH_FAILED         0x99      #define MI_WRONG_LOAD_MODE          0x97      #define MI_WRONG_DESKEY             0x96      #define MI_MKLOAD_FAILED            0x95      #define MI_FIFOERR                  0x94      #define MI_WRONG_ADDR               0x93      #define MI_DESKEYLOAD_FAILED        0x92      #define MI_WRONG_SEL_CNT            0x8F      #define MI_RC531_WRONG_READVALUE    0x8E      #define MI_WRONG_TEST_MODE          0x8C      #define MI_TEST_FAILED              0x8B      #define MI_TOC_ERROR                0x8A      #define MI_COMM_ABORT               0x89      #define MI_INVALID_BASE             0x88      #define MI_MFRC_RESET               0x87      #define MI_WRONG_VALUE              0x86      #define MI_VALERR                   0x85     #define                HIGH            1     #define                LOW                0     uint8_t    charPcdRequest(unsigned char req_code,unsigned char *pTagType);    //寻卡函数     void SetBitMask(uint8_t   reg,uint8_t   mask);     void    ClearBitMask(uint8_t reg,uint8_t mask);     uint8_t ReadRawRC(uint8_t Addr);     void WriteRawRC(uint8_t   Addr, uint8_t  Data);          uint8_t charPcdAnticoll(unsigned char *pSnr);     int8_t PcdComMF522(uint8_t   Command,                   uint8_t *pIn ,                   uint8_t   InLenByte,                  uint8_t *pOut ,                   uint32_t *pOutLenBit);     int8_t PcdReset(void);     void InitRc522(void);     int8_t M500PcdConfigISOType(uint8_t   type);     void PcdAntennaOff(void);     void PcdAntennaOn(void);          uint32_t Rc522_read_uid(void);      #ifdef __cplusplus } #endif #endif

  • 2019-06-16
  • 发表了主题帖: 氮化镓晶体管在高速电机驱动领域开辟新前沿

          与开关模式电源不同,三相电机驱动逆变器通常使用低开关频率;只有几万赫兹。大功率电机尺寸较大,具有高电感绕组;因此,即使在低开关频率下,电流纹波也是可以接受的。随着电机技术的进步,功率密度增加;电机的外形尺寸变小,速度更快,需要更高的电频率。       具有低定子电感的低压无刷直流或交流感应电机越来越多地或专门用于伺服驱动、CNC(计算机数控)机器、机器人和公用无人机等精密应用中。为了将电流纹波保持在合理范围内,这些电机——由于其低电感——要求高达100kHz的开关频率;相电流纹波与PWM(脉冲宽度调制)开关频率成反比,并转换为机械中的转矩脉动,产生振动,降低驱动精度和效率。 那么工程师为什么不增加开关频率呢?正如工程中的一贯原则,这是一种折衷的做法。逆变器的功率损耗主要包括传导损耗和开关损耗。您可以通过减小开关元件(通常为MOSFET)的尺寸来降低给定工作频率下的开关损耗,但这会导致传导损耗增加。        在理想设计中,最高可实现效率受到半导体开关的技术的限制。使用传统的基于低压48V硅MOSFET的逆变器,40kHz PWM下的开关损耗可能已明显高于传导损耗,从而构成了整体功率损耗的绝大部分。为了耗散多余的热量,需要更大的散热器。不幸的是,这增加了系统成本、重量和解决方案总尺寸,这在空间受限的应用中是不期望的或不可接受的。 氮化镓(GaN)高电子迁移率晶体管(HEMT)具有优于硅MOSFET的多种优势,开辟了新的可能性。GaN晶体管可以实现高得多的dV/dt压摆率,因此可以比硅MOSFET更快地切换,从而显著降低开关损耗。GaN晶体管的另一个优势是没有反向恢复电荷,传统硅MOSFET设计的反向恢复电荷会导致开关节点振铃。表1比较了硅FET和GaN FET。   参数 Si-FET TI的GaN (HEMT) 备注 元件结构 竖向 横向   具体 RDS(ON), 面积 >10mW-cm2 5-8mW-cm2 更低的传导损耗。 栅极电荷QG ~4nC-W ~1-1.5nC-W 降低栅极驱动器损耗,实现更快的开关速度,降低开关损耗和死区失真。 输出电荷QOSS ~25nC-W ~5nC-W 更低的输出电容可实现更快的开关速度并减少开关充电损耗 反向恢复QRR ~2-15mC-W 无 零反向恢复能够实现高效的半桥逆变器,并减少/消除硬开关中的振铃。 表1:硅功率MOSFET和TI的GaN FET(HEMT)对比   如果用新的GaN FET完全替换现有的硅MOSFET,就享受带来的益处,世界会变得轻松简单。例如,在栅极驱动电路和印刷电路板(PCB)布局中实现高压摆率具有独特的挑战性。如果处理不当,更高的dV/dt意味着增加电磁干扰(EMI)。通道之间的传播延迟失配将限制最佳可实现的死区时间,从而妨碍GaN FET实现其最佳性能。 TI的LMG5200 GaN功率级通过将两个80V/10A 18-mΩGaN FET与栅极驱动器集成在相同的无键合6mm x 8mm四方扁平无引脚(QFN)封装中,克服了这些困难。封装引脚设计为低功耗回路阻抗,PCB布局简单。输入为5V TTL和3.3V CMOS逻辑兼容,并具有2ns的典型传播延迟失配。这使得能够实现非常短的死区时间,减少了损耗和输出电流失真。 用于高速驱动的TI设计48V / 10A高频PWM 3相GaN逆变器参考设计实现了具有三个LMG5200 半桥GaN功率模块的B6逆变器拓扑结构。图1为简化框图。本参考设计提供了一个TI BoosterPack™模块兼容接口,用于连接到C2000™微控制器(MCU)LaunchPad™套件,以便进行性能评估。     图1:高频三相GaN逆变器参考设计   了解了这么多的理论,您是否对在实践中能实现多快的切换感到好奇呢?图2显示了压摆率约为40V/ns的开关节点。尽管切换速度超快,开关节点过冲小于10V。与传统的硅FET设计不同,这需要在FET的VDS击穿电压和允许的最大Vbus电源电压之间有较小的裕量。     图2:48V输入和10A负载时的开关节点   非常高的压摆率使基于分流的同相电流测量也具有挑战性。具有基于分流的在线电机相电流检测的48V三相逆变器参考设计通过使用TI的INA240差分精密电流检测放大器解决了这个问题。INA240具有-4V至80V宽的共模范围和增强的PWM抑制;在50kHz时其交流共模抑制比(CMRR)为93dB,其DC CMRR为132dB。 在最大负载电流为7ARMS时,参考设计板的功耗为4.95W,使用的PWM频率为40kHz,使用100kHz PWM时功耗为5.65W。图3为作为输出电流的函数的功率耗散。在最大输入功率为400W时达到48V总线的理论最大效率。这使得在7ARMS相电流下的相间电压为34VRMS,并且在100kHz下的逆变器效率为98.5%。     图3:氮化镓参考设计在48V与三相RMS输出电流时的功率损耗   由于高开关频率和快速电流控制环路,相电流非常接近正弦曲线,显示出较小的失真。这最大限度地减少了转矩脉动、可闻噪声,同时可提供最高的效率。图4为电流波形与施加的PWM电压的关系曲线。     图4:1kHz正弦相电流使用100kHz PWM失真较低   我们热切期望一睹具有创新精神的新应用工程师利用这新技术的力量能够创造出何种产品。 其它信息 发现TI的GaN解决方案。 阅读白皮书: 《使用集成驱动器优化GaN性能》。 《GaN FET模块与硅模块相比的性能优势》

  • 发表了主题帖: 通过调节稳压器优化 DSP 功率预算

           系统级节电与功率预算优化是许多应用的关键。例如,数据中心运营商努力控制能耗,便携式设备设计人员力图降低流耗实现更长的电池使用寿命,而通信系统则需要降低工作温度提高稳定性。电源设计主要规范的当前着眼点是: 1)在整个负载电流范围内最大限度提高效率; 2) 根据负载需要自适应缩放输出电压。 使用电压识别 (VID) 调节输出电压是满足这些需求的方法之一。当然,在英特尔和 AMD 提供的众所周知的自适应电压缩放 (AVS) 规范基础上,VID 可编程性已经在微处理器应用的 DC/DC 内核电压稳压器中得到了广泛使用。然而,这些 VID 控制器建立在多相位降压拓扑基础之上,在特性上专门围绕超大电流需求进行了定制。 DSP、FPGA 以及 ASIC 现在具有类似的功能,可根据器件活动、电源及时钟域配置、工作模式以及工作温度,实现最大限度的功耗降低。虽然支持 VID[1] 的数字化脉宽调制器 (PWM) 控制器解决方案可用来满足这一需求,但确实也需要对无处不在地模拟控制负载点 (POL) 稳压器进行输出电压数字化调节。在调节过程中,可轻松调整模拟电源实施(或许已经完成设计或已经通过测试台测试),满足其它方案无法实现的系统级功率预算与成本目标要求。 数字输出电压调节 鉴于上述设计目标中的优势利益,TI 现在提供一款 VID 编程器[2]作为专用标准产品 (ATSP)。图 1 是用于补充模拟型 POL DC/DC 解决方案的 LM10011,其包含高精度数字可编程电流数模转换器 (IDAC),支持模式可选 4 位及 6 位 VID 接口。IDAC_OUT 引脚的精确 DC 电流与 4 位或 6 位数字输入字成比例,可输入到输出稳压环路的反馈 (FB) 节点。随着输入字的累加,IDAC_OUT 电流可降低,从而可根据稳压器反馈电阻器调高输出电压设置点。FB 节点一般由模拟控制环路的误差放大器保持在恒定电压下。   图 1:常规 POL 稳压器与电流 DAC 配对,构成 6 位数字 VID 接口 该实施过程中最为重要的是 VID 解决方案与模拟 POL 稳压器设计方案的兼容性。POL 可有效部署为 DSP 的从设备。根据设计,该 IDAC 解决方案可帮助 DSP 及其它数字负载实现其全面的节电性能,降低功耗,例如在通信基础设施应用中。实际上,该款 VID 解决方案主要用于与任何 POL 稳压器一起工作,调节 KeyStone™ 多核 DSP [3] 等支持 VID 功能的处理器的内核电压 (VCORE)。 DSP 内核电源 图 2 是同步降压 POL 稳压器提供的、具有内核电压 CVDD 的多核 DSP 原理图。电源级包括 15A 电压模式稳压器、560nH 电感器以及陶瓷输入输出滤波器电容器[2]。来自 DSP 的 6 位 VID 命令有助于根据 DSP 性能要求的不断变化调节输出电压 VOUT。   图 2:使用可调节性受 VID 控制的同步降压稳压器为支持内核电压轨的多核 DSP/SoC 平台供电 根据图 2 所示的系统实施方案,具体控制方案针对 6 位 VID 使用了 4 线 (VCNTL) 接口,从而可在 VID 工作中实现更高的分辨率或精细粒度。IDAC_OUT 电流具有 59.2µA 的最大满量程范围 (VID[5:0] = 000000b = code 0)。在 6 位模式下,这可提供分辨率为 940nA 的 64 种设置以及优于 1% 的误差精度。 输出电压由 DSP 判定为电压介于 0.7V 至 1.103V 之间的电平。这相当于 VOUT 调节分辨率为 403mV/63 或 6.4mV。压摆限制可防止输出发生突变。而 VID 的抗尖峰脉冲滤波器则可提供噪声抗扰度(实际上是在 VID 线路的转换与 IDAC_OUT 电流的后续变化之间添加一个小小的延迟)。在接收到 VID 命令之前的启动过程中,IDAC_OUT 电流可根据 RSET 值,假设为 16 个分立电平之一。这允许 DSP 的内核电压在各种电平下上电,实现更高的系统灵活性与可靠性。 但值得注意的是具体的 DSP 可能无法支持所有的电压或范围。例如对 KeyStone I DSP 而言,预期工作范围在代码 31 和 50 之间(0.905V 至 1.020V)[4]。图 2 中 LM10011 的电源电压来自输入总线。另一种选项是使用 PWM 控制器提供的、或系统中其它地方(如果有)提供的额定 3.3V 或 5V 偏置电压轨。无需在 DSP 和电流 DAC 之间使用电平转换器或胶合逻辑。 图 3 是有关 VID 接口及相关定时细节更加详细的说明。VCNTL[2:0] 可为每个 VID 代码承载两位数据。处于低或高电平的 VID 分别可用来选择较低及较高的数位,而处于高电平的 VIDS 也可锁存 VID 命令,从而可使用 40µs 时间常数初始化 IDAC_OUT 的电流变化。因此每次电压调整都要求从 DSP 到控制器的两次对头拼接的访问。第一次访问写入较低的三位,第二次访问写入较高的三位。   图 3:6 位模式 VID 通信定时图 使用 VID GUI 软件[5]可记录启动时输出电压波形和跟随高、低 VID 转换的瞬态响应,如图 4 所示。输入电压为 5.3V。和预想的一样,输出电压转换发生在 VIDS 信号的上升沿。   图 4:a) 单调启动到预设值;b) 跟随 VID 转换 31 dec-50dec-31dec 的输出电压。 总结 本文中我们简单浅显地探讨了与 DSP 功率预算优化有关的种种挑战,介绍了一种通过 VID 接口来使用低成本模拟 POL 控制器的简单方法。文中包括主要的设计注意事项与电路实施。这种方法复杂性低,简单易用,适用于功率及 BOM 优化的应用,可充分满足其随时存在的上市时间及成本限制需求。简单、准确和低成本是重要的设计指标。   参考资料 了解有关 LM92x 数字电源控制器的更多详情; LM10011 VID 编程器; 观看本视频,深入了解第一个 VID 编程器; 进一步了解支持 SmartReflex 的 KeyStone 多核 DSP SoC; 下载 KeyStone I 器件的硬件设计指南; 下载 LM10011 GUI 设计工具软件。

  • 发表了主题帖: 嵌入式视觉引擎和 DSP 库拓宽TI驾驶辅助系统

          一组丰富齐全的硬件设备驱动程序和一套适用的开发工具,可帮助用户依靠 TI 的异型架构打造更加高效的先进驾驶辅助系统 (ADAS) 实施方案。基于 TI  SYS/BIOS RTOS 的TI 视觉 SDK 能够在众多的异型内核上并行运行多种算法,并更加容易地将新功能集成到系统之中。此外,丰富齐全的调试与仪表测量特性还允许算法开发人员在系统环境中对其算法进行基准测试和特性描述。         另外,TI 还在 TDA2x 片上系统 (SoC) 上提供了可用于其嵌入式视觉引擎 (EVE) 和数字信号处理器 (DSP) 的程序库。这些程序库包含了 200 多种用于 EVE 和 DSP 库的优化功能,从而为客户及第三方提供了旨在实现跨越式开发和加快产品上市进程的构件。EVE 和 DSP 库可用于中低级和高级视觉处理。在 2014 年国际消费电子展 (CES 2014) 上,TI 进行了一项环绕视图演示,以及采用 EVE 和 DSP 库构建的业界首例 1080p60 密集光流的实时演示。   类别 EVE 和 DSP 库范例 低级处理 积分图像,梯度,形态运算,直方图 中级处理 HoG,rBRIEF,ORB,Harris, 光流 高级处理 卡尔曼 (Kalman) 滤波,自适应强度算法 (Adaboost)   TI 的 TDA2x 系列 整合了创新 Vision AccelerationPac 的 TDA2x 在低功耗封装中将高性能、视觉分析、视频、图形以及通用处理内核进行完美结合,可实现从入门级到高性能的广泛 ADAS 应用。此外,TI 独特的 Vision AccelerationPac 能够以相同的功率预算实现超过 8 倍的计算性能,从而在更低成本下充分满足高级视觉分析的需求。Vision AccelerationPac 建立在 TI 丰富的算法知识基础之上,并专为满足 ADAS 市场的动态需求而设计,其包含一个或多个嵌入式视觉引擎 (EVE),可提供目前市场上其他同类产品所无法提供的特制 ADAS 加速器。   稳健的第三方生态系统 TI SoC 和软件产品库的壮大促使越来越多来自世界各地的 ADAS 第三方供应商在 TI 宽广的产品线上提供算法、服务和集成支持,从而使客户能够缩减内部投资和开发时间,并加速产品上市进程。该第三方生态系统中的很多厂商都使用了 TI 的 ADAS 处理器,并对最新 TDA2x 产品的发布表示极大的欢迎:   ADASENS Automotive GmbH 的研发总监 Michael Stoecker 说:“TI 的 EVE 为诸多 ADAS 机器视觉算法提供了令人印象深刻的性能,例如:根据运动来识别交通信号、车辆或行人以及建筑物。”   IAV Automotive Engineering 的资深项目经理 René Röllig 说:“TDA2x SoC 与 SDK 的组合使得我们能够开发下一代的 ADAS 系统,从而及时满足基于摄像头的视觉系统不断攀升的特性与性能要求。TI 的生态系统让我们可以高效地实现算法和应用,这在以前是做不到的。新型 EVE 是一款功能强大的伙伴加速器,其运作既可与独立于 DSP,也可与 DSP并行。它在我们的目标应用中展现了其全面的性能,尤其是针对基于帧的图像处理。开发工具、库和文档都是最新的,由于其品质卓越,所以我们的工程师很喜欢使用这些工具。”   TCS 的工程与工业服务全球总监 Regu Ayyaswamy 说:“凭借深厚的技术与汽车工业专长,Tata Consultancy Services (TCS) 公司在 TI 的 ADAS SoC(包括最新推出的 TDA2x)上为全球汽车 OEM 厂商及汽车零部件一级供应商提供了优化、集成服务和算法。在 ADAS 解决方案的开发方面,TI 是我们的战略合作伙伴,我们期待不断地开发出市场最需要的解决方案。”   Supercomputing Systems AG 的嵌入式与汽车产品部主管 Felix Eberli 说:“ 每一代 TI ADAS SoC 性能的大幅跃升都让我感到兴奋。已经证明:这对于我们针对不同的汽车零部件一级供应商和 OEM 厂商而移植到 TI SoC 的大量 ADAS 算法是有益处的。一个关键的差异化因素是具有高吞吐量和零开销背景数据传输特性的节能型 EVE 内核。” CSSP Inc. 总裁 Chao-Jung Chen 博士说:“TI 一直在为 ADAS 领域提供业界最佳的 SoC,因而使得我们的团队能够在 TI 的 SoC 平台上开发出生产质量的 ADAS 算法以提供给 TI 的客户,如车道偏离告警、前部碰撞告警和盲点探测。今后,我们将致力于在 TI 的下一代 TDA2x 平台上提供我们的最新算法,以利用单颗芯片实现多重功能。”   D3 Engineering 的总裁兼首席技术官 (CTO) Scott Reardon 说:“TI TDA2x 中的 EVE 以低功耗为 ADAS 应用中的视觉和视频分析算法提供了无与伦比的计算性能。EVE 软件工具的集成连同 Code Composer Studio IDE 一起简化了我们的工作流程,而其提供的范例则有助我们很快地在嵌入式 ADAS 应用中运用 EVE 所具备的强大功能。”   支持 ISO 26262 功能安全性的解决方案 TDA2x 正在按照 ISO 26262 功能安全性标准的相关要求开发。配套的安全文档将通过器件 PPAP 及新闻稿为客户提供。

  • 发表了主题帖: 探秘DLP® NIRscan™ Nano评估模块

          作为工程师和开发人员,我们的工作就是找到一个将所有元件组合在一起的最佳方法。不管是对于摩天大楼、还是集成电路,内部工程结构都是决定是否能够运转良好的关键之一。但说回来,又有谁不曾幻想做个“破坏王”,把东西都拆开来一探究竟呢?我们最初的与工程设计有关的记忆大部分都来自小时候把看起来复杂——甚至是昂贵——的东西拆得七零八落。       既然如此,我们就打算看一看DLP NIRscan Nano评估模块(EVM)的内部构造,我们将用老办法——拆开它。       需要注意的是,任何对光引擎的拆解都会使NIRscan Nano EVM的保修失效。另外,去掉光引擎上的罩子会使灰尘和污垢聚集在光学器件上,从而影响到系统性能。此外,去掉上面的罩子会移动光学器件、狭缝和探测器,导致这些元件错位,从而需要厂家重新进行对准和校准。而一旦拆除狭缝,则需要把InGaAs探测器和DLP2010NIR返厂进行系统对准与校准。   总之一句话,这事儿不能在家里尝试。          我们先来快速浏览一下。基于DLP的分光计用一个针对波长选择的数字微镜器件(DMD)和单点探测器取代了传统线性阵列探测器。通过按序打开与特定波长光相对应的一组镜列,对应光线被指向探测器,并被捕获。通过扫描DMD上的一组镜列,可以计算出吸收光谱。   近红外(NIR)光谱分析内的DLP技术可提供以下优势:   与使用具有极小像素的线性阵列探测器相比,使用更大的单点1毫米探测器能实现更高性能。 使用单元探测器和低成本光学器件能帮助实现更低的系统成本。高分辨率DMD使得定制图形能够补偿每一个单独系统的光学失真。 更大信号的捕获不仅得益于DMD相比传统技术更大的光展量(etendue),而且也受益于其快速、灵活、以及可编程的显示模式及光谱滤波器设计。 借助可编程显示模式,DLP分光计能够: 通过控制一个镜列中的像素数量来改变到达探测器的光的强度。 通过控制镜列的宽度来改变系统的分辨率。 通过使用一组Hadamard图形完成在一个图形内捕捉多个波长的光。然后,单独的波长数据可通过解码获取。每个模式内打开DMD像素数量的50%,从而将比上面提到的列扫描方式获取的更强的信号引至探测器。 使用定制光谱滤波器来选择需要的特定波长。          目前,DLP NIRscan Nano EVM软件支持可变分辨率和Hadamard图形。暂不支持可变强度和定制光谱滤波器。   在以下这幅图片中,你可以看到DLP NIRscan Nano EVM的主要组件:     拿掉光引擎罩子后,可以看到DMD和探测器电路板:   现在,如果我们拿掉反射式模块,你可以看到狭缝:     现在,我们已经可以对这个器件“一览无余”了,让我们来看一看它是如何对光进行操纵的。         从样本上反射回的光被采集镜头所搜集,并且通过输入狭缝聚焦在光引擎上。所选择的狭缝尺寸能够平衡波长分辨率和分光计的信噪比(SNR)。这个分光计使用一个长宽分别为1.69毫米 x 25微米的狭缝。通过狭缝的光在第一组镜头上校准,通过一个885纳米长的波通滤波器,然后打在一个反射光栅上。这个与聚焦透镜组合在一起的光栅将光源色散为构成它的连续波长(多色光线)。聚焦透镜将狭缝图像展开在DLP2010NIR DMD上。这个狭缝图像的不同波长水平分布在DLP2010NIR DMD上。光学系统将900纳米的波长成像在DMD的一端上,将1700纳米的波长成像在另一端上,而在中间按顺序散开所有其它波长。           今天我们找了个借口把这个器件拆开来仔细地看了看。如需获得与DLPNIRscan Nano EVM有关的更多信息,请参考DLP NIRscan Nano用户指南。

  • 发表了主题帖: 采用嵌入式Linux主处理器的DLP® LightCrafter™ Display 2000评估模块

    DLP® LightCrafter™ Display 2000评估模块(EVM)是一款强大的入门级平台,能够让用户在智能家居显示、抬头显示(HUD)和微投影等应用中评估和设计DLP原型。 与先前的DLP技术评估模块产品不同,LightCrafter Display 2000评估模块与各种嵌入式主处理器相兼容,可以轻松实现独特的DLP技术项目的原型设计。 图 1:LightCrafter Display 2000评估模块侧视图 图1展示了带有光学引擎的完整评估模块。得益于具有与系统兼容的主机端设备驱动程序,该评估模块开箱即可使用,且支持基于Sitara™ AM3358处理器的BeagleBone Black开发板。通过使用BeagleBone Black开发板的大量通用输入/输出(GPIO)引脚,评估模块可以轻松输出带引脚的完整24位RGB888图片。这一功能确保其具有良好的色彩质量和易用性,也使得BeagleBone Black开发板成为开发智能家居应用的理想目标平台。 虽然不像BeagleBone系列那样拥有许多GPIO引脚,但第二代和第三代Raspberry Pi单板机(如图2所示)提供了对加速图形的强大支持。对性能密集型应用感兴趣的开发人员来说,这是一个很好的选择。DLP LightCrafter Display 2000评估模块采用的DLP2000芯片组拥有1000比1的良好对比度,并弥补了Raspberry Pi的图形保真度。虽然Raspberry Pi不支持开箱即用的驱动程序,但DLP LightCrafter Display 2000评估模块的外露引脚能够让您轻松开发出自己的接口,从而将系统组合在一起。 图 2:Raspberry Pi电路板 例如,您可以将DLP LightCrafter Display 2000评估模块的视频输出配置更改为RGB666。随着在Raspberry Pi上引入新的软件定义I2C总线,即使其GPIO引脚数较少,主处理器也可以承载评估模块。此外,评估模块上的“VINTF”线允许任何主处理器使用其定制的I2C电平(例如3.3V或5V)来控制系统。我们已经看到TI E2E™社区和线上的开发人员开始为Raspberry Pi开发解决方案。像Raspberry Pi一样,其他主处理器也可以连接LightCrafter Dispay 2000评估模块接口,以满足各种项目需求。

  • 2019-06-14
  • 发表了主题帖: TMS320C6000系列中断

    一、 简述       本文介绍TMS320C6000系列中断设置的简明方法。通过示例定时器中断,MCBSP串口接收中断及外部中断这三种中断实现过程,介绍如何实现中断各个寄存器的配置,中断向量表书写以及中断服务函数。最后提供一个简要的示例程序可供大家下载使用。此示例在DSK6416的TI官方实验板上通过测试。由于定时器和串口工作模式较繁,因此对中断无关部分不做介绍。 二、 实现DSP中断需要做哪些通用工作 设置允许哪些非屏蔽中断 设置各个允许的非屏蔽中断的中断来源 设置开启总中断 设计中断向量表 将中断向量表通过cmd文件挂载到指令内存 提供中断处理函数 如果中断向量表首地址挂载的不是地址,那么需要设置中断向量表地址寄存器 对于不同的中断源,需要做各个自己的工作,比如如果是外部中断,那么需要设置管脚极性,即由高->低产生中断抑或反之。 为了照顾知识较少的读者,下面将从一个新工程出发,引导大家建立一个中断示例程序。 如果您对建立工程很熟悉,可以跳过此步。 三、 建立新工程       1.点击Project->New,设置Project Name为intexample,Project Type为Executable,Target选择您需要的器件,在此由于本人使用的是DSK6416评估板。因此选择TMS320C64XX。      2.添加标准库rts6400.lib,以便自动产生c_int00等函数。右击当前工程,选择“Add Files to Project”,选择库所在路径,一般为CCS安装自带,可参考本CCS3.1版本的路径地址:\CCStudio_v3.1\C6000\cgtools\lib\rts6400.lib 如果您使用的是其他器件类型,请在lib文件夹内选择其他器件库。 添加源文件,选择File->New->Source File,保存为main.c到工程路径下。 在此文件内书写主函数。 void main(void) {  while(1); } 最后通过如2步骤添加此文件到工程。       3.添加寄存器别名定义头文件。在本示例中,对需要用到的寄存器定义别名后,构成global.h文件,内容在后文逐步介绍。在此可以建立一个空文件,并在main.c中包括它。 #i nclude "global.h" 到此,一个DSP的新工程框架制作完毕。       4.添加cmd链接文件  为了实现链接时内存配置,我们需要提供一个cmd文件,为了方便,可以从官方的示例程序中拷贝一份,再加以修改。  在安装目录下D:\CCStudio_v3.1\tutorial\器件类型\hello1示例下,会找到一个hello1.cmd,  将其拷贝到本工程目录下,并将其改名为link.cmd,最后将其添加到工程中。  由于此文件没有声明stack和heap,会产生警告,如果动态数据较多也容易溢出。因此我们最好在此文件提供stack和heap的大小,其值可根据实际情况调整,修改后,此文件内容类似为: -stack 0x1000 -heap 0x1000 MEMORY  {    ISRAM       : origin = 0x0,         len = 0x1000000 } SECTIONS {         .vectors > ISRAM         .text    > ISRAM         .bss     > ISRAM         .cinit   > ISRAM         .const   > ISRAM         .far     > ISRAM         .stack   > ISRAM         .cio     > ISRAM         .sysmem  > ISRAM } 至此,工程建立完毕,可以编译一遍,观察是否正常。 ---------------------------  intexample.pjt - Debug  --------------------------- [main.c] "D:\CCStudio_v3.1\C6000\cgtools\bin\cl6x" -g -fr"D:/intexample/Debug" -d"_DEBUG" -mv6400 -@"Debug.lkf" "main.c" [Linking...] "D:\CCStudio_v3.1\C6000\cgtools\bin\cl6x" -@"Debug.lkf" <Linking> Build Complete,   0 Errors, 0 Warnings, 0 Remarks. 四、 定时器中断设计        首先,我们先实现一个定时器中断,因为它不受外部影响,容易测试。 在global.h文件中,加入控制寄存器和中断寄存器别名定义,另外为了使用定时器1,也应对其别名进行定义: /*定义控制寄存器*/ extern cregister volatile unsigned int AMR;     /* Address Mode Register      */ extern cregister volatile unsigned int CSR;     /* Control Status Register    */ extern cregister volatile unsigned int IFR;     /* Interrupt Flag Register    */ extern cregister volatile unsigned int ISR;     /* Interrupt Set Register     */ extern cregister volatile unsigned int ICR;     /* Interrupt Clear Register   */ extern cregister volatile unsigned int IER;     /* Interrupt Enable Register  */ extern cregister volatile unsigned int ISTP;    /* Interrupt Service Tbl Ptr  */ extern cregister volatile unsigned int IRP;     /* Interrupt Return Pointer   */ extern cregister volatile unsigned int NRP;     /* Non-maskable Int Return Ptr*/ extern cregister volatile unsigned int IN;      /* General Purpose Input Reg  */ extern cregister volatile unsigned int OUT;     /* General Purpose Output Reg */ /* 定义中断选择寄存器*/ #define MUXH 0x019C0000 #define MUXL 0x019C0004 #define EXTPOL 0x019C0008 /*定义定时器1寄存器*/ #define CTL1 0x01980000     //Timer1 control register #define PRD1 0x01980004     //Timer1 period register #define CNT1 0x01980008     //Timer1 counter register 之后,在main函数中对定时器进行初始化,在此我们使用Timer1,参数初始化函数如下: void Timer1_Init(void) {  *( volatile unsigned int* )CTL1= 0x00000201;  //计数器功能设置  *( volatile unsigned int* )PRD1= 0x1000;   //计数器周期值  *( volatile unsigned int* )CTL1|= 0x000000C0;  //计数器清零,启动 上句的注释:*( volatile unsigned int* )CTL1=CTL1|0x000000C0 } 并在主函数中调用它。 随后我们设置中断寄存器参数。 DSP支持1个RESET中断,1个NMI(不可屏蔽中断),12个可屏蔽中断(INT4-15),它们具有优先级顺序,INT4最高,INT15最低。每个中断号(INT4-INT15)都可以设置任何中断来源。在此我们选择中断INT10,即开启中断10,并设置其中断来源为定时器1,即在MUXH或MUXL中指定位上填写中断来源选择码: 中断来源选择码定义如下:(此内容可以通过帮助中搜索INTSEL得到) INTSEL(Interrupt Selection Number Deion) 00000b   DSPINT                            Host port host to DSP interrupt 00001b   TINT0                             Timer 0 interrupt 00010b   TINT1                             Timer 1 interrupt 00011b   SD_INT                            EMIF SDRAM timer interrupt 00100b   EXT_INT4                          External interrupt 4 00101b   EXT_INT5                          External interrupt 5 00110b   EXT_INT6                          External interrupt 6 00111b   EXT_INT7                          External interrupt 7 01000b   EDMA_INT                         EDMA channel (0-15) interrupt 01001-01011b                                 Reserved 01100b   XINT0                             McBSP0 transmit interrupt 01101b   RINT0                              McBSP0 receive interrupt 01110b   XINT1                              McBSP1 transmit interrupt 01111b   RINT1                              McBSP1 receive interrupt 10000-11111b                                 Reserved 从中得到定时器1的中断选择码为00010。 MUXH和MUXL的寄存器定义如下:(也可以通过帮助得到)  MUXH  位                                  中断来源 30-26                                INTSEL15 25-21                                INTSEL14 20-16                                INTSEL13 14-10                                INTSEL12 9-5                                   INTSEL11 4-0                                   INTSEL10 31,15                              保留,填   MUXL  位                                   中断来源 30-26                                 INTSEL9 25-21                                 INTSEL8 20-16                                 INTSEL7 14-10                                 INTSEL6 9-5                                    INTSEL5 4-0                                    INTSEL4        //中断INT4的中断来源,选择定时器中断 31,15                               保留,填 因此,我们设置MUXH的第4-0位为定时器1的中断选择码00010,其余位可以任意设置(在此可以填1)。转换为16进制后,设置如下:  *( volatile unsigned int* )MUXH=0x7fff7fe2; MUXL可以不设置。 开启中断到IE10,使能全局中断:  IER |= 0x0000 0402;   // IE10=1   CSR |= 0x00000001;   // 全局中断使能 以上就完成了中断参数的配置,中断启动并且可以进入了。下面是中断的处理过程。主要分为设计中断向量表和中断处理函数。 我们可以从DSP CCS的示例中复制一份向量表的雏形。例如\CCStudio_v3.1\tutorial\dsk6416\hello1\vectors.asm 将其拷贝到本工程目录下并加入工程中。 中断向量表包含了16个中断处理单元,每个单元限制必须是8条指令。如果不够8条,可以用nop填充,(但nop 4算1条语句),如果服务程序过多,那么可以制作专门的中断服务程序,此时此表只起到跳转作用,这样CPU就可以正确寻址找到正确的中断服务入口。  首先分析一下此文件。 文件开始定义了一个宏,用于处理未用到的中断。 unused  .macro id         .global unused:id: unused:id:         b unused:id:    ; nested branches to block interrupts         nop 4         b unused:id:         nop         nop         nop         nop         nop 它的做法是让程序进入死循环,我认为这种做法未必最优,因此我建议使用直接返回的方式。返回到被中断地址,对于可屏蔽中断为b irp,因此将此宏部分替换成,注意一定要凑够8条。 unused  .macro id         .global unused:id: unused:id:         b irp         nop         nop         nop         nop         nop         nop   nop         .endm 这样,即使我们误开启了此中断,也会顺利返回。当然,如果我们确信的确没有开启,那么其内容是无意义的。 代码的正文部分用了一系列unused n来插入此宏,起到占地的作用。 由于NMI的返回与可屏蔽中断不同,它在向量表中位于RESET之下,即unused 1,我们将其删除,替换为 NMI:    b irp   nop   nop   nop   nop   nop   nop   nop 为了实现定时器1中断的处理,我们将unused 10删除,替换为我们自己的中断跳转程序,如下: INT10:   stw b0,*--b15   mvkl _xint0_isr,b0   mvkh _xint0_isr,b0   b b0   ldw *b15++,b0   nop 3   nop   nop 另外,需要和语句:         .ref _c_int00           ; C entry point 类似,添加处理程序的引用   .ref _xint0_isr   ; timer 1 interrupt handler 由于中断向量表的位置需要特定指明,且应对齐到400H,在此文件中,已经定义了段名:         .sect ".vectors" 因此我们需要将此.vector代码段挂载到专门的一段指定内存区域。 修改link.cmd 链接文件,加入INT区域,起点为地址。其大小为400H,将原先的ISRAM起始点修改。并将SECTIONS中的.vector指向自己定义的内存区域。 MEMORY  {    INT         : origin = 0x00000000,  len = 0x0000400    ISRAM      : origin = 0x00000400,  len = 0x1000000 } SECTIONS {         .vectors > INT … } 中断向量表设置、安装完毕。 最后,设计中断服务函数,在main.c中添加: interrupt void xint0_isr(void) { } 注意,一定要标识interrupt关键字,用于产生中断返回语句b irp,同时,此函数的入口参数和出口参数应为void。如果需要更新变量,可以通过全局变量的方式。 另外,C语言函数名称与汇编相差一个“_”,请在设计中断向量表时注意添加。 经过上述步骤,整个定时器中断的制作过程就完成了。此时可以在interrupt void xint0_isr(void)上添加一个断点,运行后应该停在此处。如果进入失败,可以先在vector.asm的INT10:stw b0,*--b15一句上设置断点,如果没有进入此处,证明中断没有进来,可以检查是否在参数设置上出现了问题。 五、 外部中断设计 DSP6000系列提供了INT4-7四个中断输入管脚,因此可以通过此四个管脚的输入电平变化实现外部中断。对于电平变化的极性,分为高到低,低到高两种,因此,DSP采用寄存器EXTPOL来设置。EXTPOL只有低4位有效,分别代表INT4-7,对于每个位有: :低->高产生中断 1:高->低产生中断 因此设置它即可完成极性变化。 下面,以设置外部端口INT7中断,并将其挂载到12号中断为例,简述实现过程: 将12号中断设置为外部中断7,即MUXH(14:10)=00111,此时MUXH设置为:  *( volatile unsigned int* )MUXH=0x7fff7ce2;//0111 1100 1110 0010 将IER的第12位开启。   IER |= 0x00001402;   // IE10=1 IE12=1 对vectors.asm的unused 12替换为: INT12:   stw b0,*--b15   mvkl _extint7_isr,b0   mvkh _extint7_isr,b0   b b0   ldw *b15++,b0   nop 3   nop   nop 并添加引用 .ref _extint7_isr 在main.c中加入服务函数: interrupt void extint7_isr(void) { } 在硬件上,对INT7/GPIO7管脚产生一个低->高的信号,则可以触发出中断。 若改变此极性,可以设置EXTPOL第四位为1:   *( volatile unsigned int* )EXTPOL|= 0x00000008; 此时,一个高->低的信号可以产生中断。  需要注意的是,如果你对GPIO进行过初始化,一定要保证GPEN的中断引脚相应位为1。如全部使能:    *(volatile unsigned int* )GPEN = 0x000000F0;  六、 MCBSP串口接收中断设计 在实际应用过程中,经常需要通过中断接收串口数据。在此假设添加MCBSP0接收中断到11号。 首先,将MCBSP0别名添加到global.h文件。 设置MCBSP0参数并启用,其初始化函数为: void MCBSP0_Init(void) {  *( volatile unsigned int* )McBSP0_SPCR  = 0x00000000;  *( volatile unsigned int* )McBSP0_SRGR  = 0x200000FF;  *( volatile unsigned int* )McBSP0_PCR = 0x00000800;  *( volatile unsigned int* )McBSP0_XCR = 0x000100A0;  *( volatile unsigned int* )McBSP0_RCR = 0x000100A0;  *( volatile unsigned int* )McBSP0_MCR  = 0x00000000;  *( volatile unsigned int* )McBSP0_SPCR  |= 0x00C10001; } 并在main函数中调用。 开启中断11:  IER |= 0x00001C02;   // IE10=1 IE11=1 IE12=1 并将MUXH(9:5)=01101,综合以上三个中断, 此时MUXH为: *( volatile unsigned int* )MUXH=0x7fff1da2;//0001 1101 1010 0010 当然,如果只考虑现在的中断,MUXH可以设置为:  *( volatile unsigned int* )MUXH=0x7fff7dbf;//0111 1101 1011 1111 制作中断服务程序,将数据取出: interrupt void rint0_isr(void) {  int DotRev;  DotRev=*( volatile unsigned int *)McBSP0_DRR; } 修改vectors.asm,替换unused 11为: INT11:   stw b0,*--b15   mvkl _rint0_isr,b0   mvkh _rint0_isr,b0   b b0   ldw *b15++,b0   nop 3   nop   nop 添加引用:   .ref _rint0_isr   ; mcbsp 0 receive interrupt handler 这时,所有的任务完成了,可以通过设置断点观察一下接收的数值。 另外需要注意一定要在服务程序中将数据取出,否则会停止接到新的数据。 七、 其他话题 1.设置中断向量表起始位置 上文讨论的都是将中断向量表放置在地址,如果需要放置到任意地址(以400H对齐),那么就需要提供向量表起始地址。 比如我们的终端向量位置:INT设置为: MEMORY  {    INT         : origin = 0x00000400,  len = 0x0000400    ISRAM       : origin = 0x00000800,  len = 0x1000000 } 那么我们在初始化中断时,应设置:  ISTP=0x00000400; 2.查看现在的中断位图 可以查看中断标志寄存器IFR相应位(15:0)看是否有中断到达。   3.清除/设置原先的中断 如果需要清除原先的中断,可以通过对ICR寄存器相应位置位。如果希望人工触发中断,可以设置ISR寄存器相应位置位,它们将更新IFR位图。 比如,我们在定时器中断服务程序中,通过设置ISR的第12位,人工触发外部INT7的12号中断。 interrupt void xint0_isr(void) {  ISR=0x00001000; } 那么CPU将执行extint7_isr(void)处理此中断。 又比如,在上例的外部中断中,有时会出现刚一开机,没有发送信号就有中断进来的情况,那么怎样克服呢?可以通过ICR克服。对ICR置位可以清除可屏蔽中断。对应位有效。比如在设置中断初始化时清除所有原先的中断。那么可以加入语句:  ICR =0xffffffff; 4.DSP/BIOS下的中断设置 在DSP/BIOS管理下,我们不需要自己设定中断向量表,以及中断初始化等等,一切通过BIOS的图形化设置即可完成。 添加一个DSP/BIOS 选择File->New,在本测试下选择DSK6416,读者可根据自己实际需要选取。保存为Configuration1.cdb。 将其添加到工程。 如上例需求,选择HWI的10,11,12号中断,右键选择Properties分别填写如下参数: HWI_INT10  interrupt source=Timer_1  =_xint0_isr(注意下划线!) HWI_INT11 interrupt source=MCSP_0_Receive =_rint0_isr HWI_INT11 interrupt source=External_Pin_7  =_extint7_isr 在main函数中可以通过同样的方法启动中断。   IER |= 0x00001C02;   // IE10=1 IE11=1 IE12=1   CSR |= 0x00000001;   //全局中断使能 至此配置完毕。 5.中断进不来怎样检查? 首先检查是否设置IER相应位开启,CSR最低位置位,其次看看中断向量表地址是否设置正确。如果确认无误。在向量表中断应当进入的位置设定断点。运行看是否执行到断点。如果有,那么看看中断服务程序有没有执行到。如果中断只进来一次后就再也无法进入了,可以查看中断向量表是否能返回到原程序,如果不能返回,查看是否是8条语句。另外可以通过跟踪查看b irp语句是否被执行。如果可以正常返回到原程序,例如串口接收,看看是否没有取值导致阻塞。如果是这样需要将原先值取出才有新的中断。 6.中断若干寄存器的说明到哪里去找? 可以通过Help->Contents,搜索关键字的方法得到。也可以参考官方文档。 八、 附带程序 本教程以附件提供三个示例: 1. onlytimerint——仅包含了定时器的示例 2. int——包含了完整的3种中断 3. intbios——提供了DSP/BIOS下的此3种中断。 九、 参考文档 《TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide》Chapter5 interrupts  

  • 发表了主题帖: 基于单片机和触控模块的3D无线射频鼠标的设计与实现

            鼠标作为电脑的一基本部件。扮演着重要的角色。随着科技的进步和市场的需求。鼠标也经历着快速的发展。传统的鼠标无论是有线鼠标还是无线鼠标。由于采用控制原理的原因,或者受到线缆的约束,或者离不开对桌面等载体的依赖,适用场合和范围受到限制。因此,市场上急需一种适用于多种场合。能满足不同人群特殊功能需求的鼠标,此时。3D无线鼠标的概念应运而生。本文通过对运用MEMS加速度传感器。触控模块和凌阳单片机完成鼠标3D控制原理的阐述。以及对实验中实际操作的记录为现阶段多功能新型鼠标的制作提供参考依据。 1 3D无线鼠标的工作原理       无线射频鼠标总体分为发射模块(见图1)和接收模块(见图2)两个部分。发射部分模块集成在手持端,由使用者控制。接收模块与PC、笔记本等仪器相连。 图1 发射模块系统框图        发射模块主要由电阻式触摸屏、MEMS加速度传感器、16位凌阳单片机和nRF2401发射模块组成,主要功能是实现对手势运动趋势信息的采集和发送。其中触摸屏用于检测使用时坐标X、Y的变化,通过对X、Y变化趋势的分析,完成对鼠标移动轨迹的模拟。MEMS加速度传感器则用于感知使用者的动作,通过将这些动作定义为特殊指令。实现鼠标的特殊功能键。同时发射模块与接收模块之间通过2.4GHz无线收发一体芯片完成两者之问的无线通信。最终由接收端的USB驱动电路实现PC端的鼠标控制功能。        其中在通过对X、Y坐标变化,进行算法处理时,需要对操作过程中误差较大的坐标进行滤波,同时简化鼠标的移动方向。并通过固化匹配的方式,正确反映鼠标的整体的运动趋势。从而更好的完成对手势运动趋势的分析,实现鼠标的准确定位。 2 触屏检测装置与加速度传感器的硬件电路设计       在动作感应模块方面。采用鸭C2046作为四线电阻式触摸屏控制器。TSC2046以其低功耗和高速率等特性广泛应用于电池供电的小型手持设备。它与触摸屏连接的原理电路如图3所示。另一方面。采用型号为MXR9550的MEMS加速度传感器模块。它的体积小、重量轻、功耗低、可靠性高、易于集成和实现智能化,其原理电路如图4所示,利用它来感知人的动作,如挥手、摆臂等,然后可以将不同的动作定义为特殊的功能,如实现演讲时PPT、PDF的翻页,关闭窗口,切换窗口等动作。 图3 TSC2046与触摸屏连接的硬件原理图 图4 MEMS加速度传感器原理电路 3系统流程设计        在发射端。当系统上电后,控制芯片会一直检测触摸屏和MEMS加速度传感器的状态。当滑动触摸屏或是摇动鼠标时,系统就会收到数据,同时凌阳单片机通过对这些数据的处理。就能判断出手指在触摸屏上移动的轨迹和是否摇动了鼠标。然后将这些动作定义为不同的指令。通过无线模块发射出去。程序流程如图5所示。 图5手持端程序流程图        在接收端,无线模块始终等待捕捉发射信号。在接收成功后。控制芯片根据接收到的不同指令,通过USB接口电路传送给电脑。完成鼠标动作。从而实现无线鼠标工作的整个过程。程序流程如图6所示。 图6接收端程序流程图 4 鼠标手势算法设计         由于每次采集的数据很多,其中有一小部分数据存在误差,如果不将这些误差数据过滤,肯定会影响鼠标的移动轨迹。如何得到准确的触摸屏数据。是优化鼠标移动轨迹的关键。因此,在程序设计中。提出了一种优化鼠标移动轨迹的算法。其大致思路如以下:①过滤鼠标移动动作。如图7(a)所示。这步将鼠标一连串移动动作中的小幅度波动动作给去掉,这一步是十分必要的;②限制鼠标移动方向,如图7(b)所示。对于简单的鼠标手势支持,只支持上下左右4个方向。就把其他方向的动作都归并到这4个方向中。一般就是比较一下上下方向和左右方向的差值,取大的那个作为最后的方向;③简化移动方向序列,如图7(c)所示。这步非常简单,原本是右右上上右上上的方向序列,简化后变成右上右上了;(多匹配动作序列,如图7(d)所示。这步是最困难的,表面是把夹杂在长距离移动动作中的短距离动作过滤掉。实际的做法是先把整个动作序列与一组预定义的动作序列匹配比较,如果匹配失败,就把这序列中最短幅度的动作过滤掉,再进行匹配,如此循环往复,直到最后匹配到为止。 图7 手势算法演示 5  结束语       本文阐述了一种3D无线射频鼠标设汁的新思路,对传统的鼠标不但进行了实现原理的创新,同时对其操作方式进行了补充,使鼠标真正摆脱对线缆与载体的依赖成为可能。随着互联网应用的发展,移动办公的理念得到越来越多的支持,因此,本文设计的无线鼠标也能顺应了移动办公的潮流。

  • 发表了主题帖: 基于WinUSB实现的嵌入式USB免驱设备通信方式

           为了简化USB设备的开发和接入到PC系统,微软开发了WinUSB,可以将Winusb.sys作为设备功能驱动程序安装,并提供WinUSB API供应用程序访问设备。一直以来,除了USB HID设备,其他类型的设备在WINDOWS环境下需要安装驱动程序才能工作。要实现USB设备免驱,就只能使用HID设备。而HID设备传输速度慢,在有些场合必须使用Bulk类型进行批量传输时,就必须使用第三方驱动,或者自己开发一个驱动,使得项目开发非常麻烦。现在好了,自从微软推出了WinUSB,在微软的最新操作系统上实现简单的Bulk类型批量传输也变得非常的方便快捷,在研发过程当中或者一些对于差异化要求不高的场合,是非常适用且容易实现的。本文致力于实现一个最简单的WinUSB通信系统,以满足此类需求。   如何让嵌入式设备枚举成WinUSB设备   系统通过USB描述符来确定以何种USB Class类型来工作。如果希望WINDOWS能够将嵌入式设备识别为WinUSB设备,则其描述符至少应当包含以下字段:   1、支持 OS 字符串描述符:   为了让 USB 驱动程序堆栈了解设备支持扩展的特征描述符,设备必须定义存储在字符串索引 0xEE 处的 OS 字符串描述符。在枚举过程中,驱动程序堆栈查询字符串描述符。如果存在描述符,驱动程序堆栈会假定设备包含一个或多个 OS 特征描述符和检索这些特征描述符所需要的数据。检索的字符串描述符具有 bMS_VendorCode 字段值。该值为1表示USB驱动程序堆栈必须用来检索扩展特征描述符的供应商代码。   #define bMS_VendorCode ( 0x01 )   // "MSFT100" : index : 0xEE : langId : 0x0000const 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 sections0x00, 0x01, // bcdVersion   0x05, 0x00, // wIndex   0x01, 0x00, // wCount   0x84, 0x00, 0x00, 0x00, // dwSize -- this section0x01, 0x00, 0x00, 0x00, // dwPropertyDataType0x28, 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应用程序与嵌入式设备进行USB通信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免驱设备的通信方式了。

  • 发表了主题帖: 有关嵌入式DSP设计中的功耗优化设计

          对基于数字信号处理器(DSP)的系统而言,优化功耗是一项重要但往往难以实现的设计目标。现在,基于DSP的设备常常把以往各自独立的多个应用结合起来,每一个应用都可能有多个工作模式。要得到这样一个设备的功率分布是非常困难的一件事,更遑论整个复杂的系统。设计人员需要获知尽可能多的最佳信息,以及能够帮助他们优化特定应用之功耗的技术和工具。   幸运的是,近年来,在DSP芯片的设计和制造工艺方面,都在不断推出更先进的功耗降低方法。现在的片上功率优化技术能够提供更多的精细控制和更多的省电模式,以及关于处理器功耗的更完整的信息。更新型的DSP开发工具使设计人员得以更深入透彻地了解系统的功率消耗方式,并通过片上硬件来提供功耗降低技术。   为了让开发人员能够更灵活地控制省电技术,更好地协调众多片上功能间的低功率工作和时序问题,DSP操作系统整合了多项功率管理功能。这些内建功能及工具加上系统设计的精心部署,DSP系统的功耗可得到大幅度降低。   低功耗问题   低功耗对所有的DSP系统都很重要,虽然理由因具体应用而异。在网格供电系统中,降低功率就意味着降低开销、提高可靠性,以及实现紧凑型设计,从而可以在相同的空间中集成更多的功能性,同时需要更少的风扇和其它冷却技术。在高清医疗成像等关键应用产品中,器件工作产生的热量甚至可能导致运行故障,因此,低于设备最大额定值并增加对低功耗的要求是至关重要的。   在便携式电子系统中,低功耗有助于尽量减小系统的尺寸及重量,同时把电池充电后的使用时间延至最长。较小电池的使用可进一步降低系统的规模。更低的功率还有助于避免便携式系统在延时使用期间过热。因功耗降低,手机、PDA、MP3播放器、数码相机和视频摄像机这些电子仪器及其他手持式设备的尺寸都日趋纤小,工作温度越来越低,而充电后的使用时间越来越长。   理解功率分布和芯片资源   在任何类型的系统中,降低功率的第一步是了解系统的使用方式,以及这种使用是如何影响功耗的。比如,手机大部分时间都处于等待呼叫的状态中,实际通话的时间相当少。另一方面,MP3播放器通常不是开机处于激活运行状态,就是处于关断状态。其它系统、线路供电系统以及便携式系统,都有着不同的待机功耗分布和激活工作功耗分布,参见下面的图1。    了解功耗分布有助于设计人员选择一个具功率效率的处理器,因为在某些类型的应用中,DSP的基本CMOS技术可能对功耗产生很大的影响。先进的CMOS工艺则基于工作电压极低的高性能晶体管。根据既定应用,可以量身定做晶体管,通过对静态电流进行钳位把功耗降至最小,或把性能提高到最大,尽管这样会稍微增加泄漏电流。专门为手机这样的待机时间很长的应用而设计的DSP,可通过低泄漏晶体管把静态电流降至最低,而为总是处于激活状态的高性能应用而设计的DSP则较青睐开关速度更快的晶体管。   系统使用还包括系统对各种事件的响应,以及电路接通电源时的延迟。初始上电时可能有一些延迟,而系统从待机模式被唤醒时,较小的延迟是可以接受的。但用户一般都期望处于激活工作状态的系统能够即时响应,故而这时片上功能不能处于深度睡眠模式。这里有两方面的考虑:第一,部分功能可以较其它功能更彻底地关断,尤其是在待机期间,激活工作期间也如此。第二,处理器的功率模式控制能力越精细,设计人员就越能够进行充分的功耗调节以适合系统的操作情况。   高功率效率的DSP芯片设计通过建立电源域,使应用能够切断不在使用中的功能的时钟输入,从而把所有这些因素都考虑在内了。正如处理内核能够进入睡眠模式,此时它不执行任何操作,直到被中断信号唤醒,外设和存储器模块也同样可以被置于睡眠模式,在需要时才被唤醒。无时钟输入功能中的晶体管除静态电流之外,没有什么功耗,而恢复时钟所需的唤醒延迟被减至最小。系统设计人员在考虑其产品的使用情况时,还需要考虑到在为各项功能提供时钟方面,DSP能够提供多少控制能力,或是否能够自动处理。   节能DSP内建的另一项功能是能够调节核心电压和频率。如果DSP可降低核心时钟速率并仍然满足其处理要求,则工作功耗会相应地按比例节省。更低的频率加上更低的工作电压,可以节省相当可观的能量。可以在系统启动时调节电压和频率以适于整个系统的运行,也可以在应用需要改变时通过软件对之予以动态控制,这就为非峰值处理期间的功耗削减提供了一种重要的手段。   正确功率信息的获得   复杂DSP系统可能具有多个内核、应用和管理模式,这使得对功率的估算极其困难。传统的功率确定方法基于某些信息来实现,比如器件数据手册上注明的最大电流值,每周期或每条指令的耗电量(mA/MHz, mA/MIPS)以及测试案例等。   这些方法只能用来做粗略估算,但对内核、外设和片上存储器可以根据应用和操作模式进行独立开关的复杂系统而言,是不足以估算DSP功耗的。设计人员需要清楚了解实际应用中片上各项功能的具体功耗,因为实际的功率信息使他们能够更加精确地估算出不同实现方案的结果,并测定出在不同平台上应用是如何影响功耗的。   在DSP制造方面,所需要的是模块化的功率估算方案,即把设备划分为若干子系统,然后独立运行每一个子系统。一旦确定了每一个片上功能的最大功率值和空闲功率值,就可以通过插值法为一个功能建立一条功耗曲线。于是,在明确了每一功能的运行级别之后,可以把从各条曲线获得的功率值累加,最后给出整个设备的实际功率估算值。   图2是一个功率估算电子数据表,它把一个典型的DSP分解为若干个子系统,由用户输入相关参数,然后可以返回设备的功率估算值。就像这个电子数据表所显示的,估算是否正确取决于用户提供的信息是否反映出对系统使用方式的良好了解,包括数据宽度、频率、电源电压和使用中外设的可用带宽的百分比等因素。       图2:功耗估算   低功耗设计   具有功耗意识的设计(Power-conscious design)技术可以帮助DSP设计人员充分利用正确的功率估算。在系统级,设计人员应该精心选择相关元件,使其数目尽可能地低。此外,设计人员还应该考虑到哪些未使用的元件可以置于省电模式,尤其是在待机期间。板级存储器的使用也是一个功率消耗源,因为必须同时给存储器芯片和电路板迹线供电。   应用应该尽可能地使用DSP的内部存储器,以保持片上大带宽存储,把外部存储器保留用作偶尔的低速存取。片外存储器也可以很好地完成启动工作,但应该在启动后被置于省电模式。为了减少存储器中的代码量和所取指令的数量,应该优化软件提升性能。更紧凑的代码有助于更好地利用缓存和内部指令缓冲器,而且运行速度更快,故能减少系统处于激活模式的时间。   大多数特定设备都是利用DSP的内建硬件能力来降低功耗的。从一启动开始,应用设备就 可以让不使用的模块处于空闲状态,外设功耗只限用于那些在指定时间才需要的I/O 。应用通常在启动时就直接控制各个模块,稍后,DSP内核可以后台执行一个循环来检测哪些功能不需要,然后把它们关断。如果应用采用了这些技术,芯片的睡眠模式就可以把空闲期间内核及芯片的功耗降至最低。   若所要求的总体性能不等于设备的全部能力,则可以在启动时就对DSP内核电压和频率(V/F)进行调节。若系统在具有不同性能负载的应用间更替,V/F调节也可以在运行期间动态进行。要实现V/F调节,设计必需提供DSP外部电源电压控制,以及内建于后台循环程序的软件控制。由于频率调节减慢内核的运行速度,设计人员在应用设计中应该考虑到相互关联的各个操作间的时序问题。   OS中的功率管理   不论是通过V/F调节还是通过低功耗模式来动态改变系统的功率要求,都需要涉及到DSP的实时操作系统(RTOS)。RTOS中的功率管理(PM)模块能够在启动时实现功耗节省,并在整个系统上协调各个低功耗操作。   内核频率调节会影响子系统操作的时序,因此PM能够在完成频率调节之后进行时钟调节。如果对应用来说OS时钟精度不重要,或者是用户希望节省空间,则可以不使用PM功能   此外,当线程被阻断时,用户还可以激活或停用自动使时钟处于空闲状态的PM功能。在其协调作用中,PM提供了一种用于功率事件通知的注册功能,当特定功率管理事件发生时,客户可以注册通知,由于系统的复杂性,PM支持多个客户端并允许客户延迟事件的完成。   PM还提供了一个应用编程接口(API)库,可实现芯片的低功率技术软件控制。通过这些API,应用能够门控时钟,激活睡眠模式并安全管理V/F调节设置点之间的晶体管。这些设置点作为调节参数,使V/F能够按照正确的顺序降低和提高,而且具有正确操作所必需的设置时间。   下面图3显示了设置点是如何控制V/F调节的时序的。由于电压和频率调节对设计中所用的DSP和电压调节器是特定的,PM API支持设置点延迟查询和配置,同时PM库可被重建。      图3:功耗调节结果   工具的辅助开发功能   要有效解决上述所有技术问题,需要一些专门为功率管理而设计的工具。类似于DSP工具开发的其它领域,功率优化工具也致力于提供可视化和易于使用的优势,以帮助简化系统分析并缩短上市时间。   这些工具结合DSP的嵌入式及RTOS功率管理技术,可以提供计量表、示波器波形、信道校准、测试代码和事件触发等等测试功能。利用这些便捷功能,设计人员可得到一个反馈机制,凭此评估各个实现方案对功耗的影响,最终获得一个最佳方案。   显示了在设计周期中,集成的硬件和工具平台,比如国家仪器有限公司(National Instruments)的C55x电源优化DSP入门套件(DSK),能够如何以及在什么地方帮助开发人员在不同的设计环境下评估DSP的功耗,从而使是他们能够更迅速地选定最适合其系统的最佳低功耗/高性能总体方案。   从一开始就进行功率设计   在系统开发中,功率优化有时被当作一项事后工作来处理,但这是不对的。在开发周期中,越早考虑功率优化问题越好,对于具有多个应用和工作模式的复杂系统而言尤其如是。为了延长电池工作时间,低功耗通常是主要的要求之一,即使是线路供电系统也需要通过降低耗电量来减少散热和运行成本。   为了优化功耗,设计人员需要了解系统的功率分布,以提供全面的参考信息源,从而在功率估算中把所有主要的系统功能都考虑在内。基于高功率效率的CMOS工艺的DSP集成了硬件技术,比如精细定义的低功率模式和电压/频率调节。API使这些技术很容易通过RTOS实现应用控制,测试工具可帮助设计人员估算出不同实现方案的功耗。利用这些资源,开发人员有充分的理由从开发周期的最开始就进行功率设计。

统计信息

已有236人来访过

  • 芯币:4537
  • 好友:--
  • 主题:1506
  • 回复:85
  • 课时:--
  • 资源:--

留言

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


现在还没有留言