如何在lpc2200 spi驱动上调试中断程序

【论文】LPC2200的嵌入式系统中断设计_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
中国最大最早的专业内容网站00.0浏览总量总评分
评价文档:
&购买后可评价
2页¥1.004页¥2.003页¥2.004页¥2.003页¥1.004页¥2.002页¥3.003页¥2.005页¥2.003页¥2.00
您可以上传图片描述问题
联系电话:
请填写真实有效的信息,以便工作人员联系您,我们为您严格保密。
LPC2200的嵌入式系统中断设计嵌​入​式​微​处​理​器​的​应​用​设​计​中​,​中​断​处​理​通​常​是​系​统​的​核​心​任​务​之​一​。​A​R​M​作​为​嵌​入​式​微​处​理​器​的​典​型​代​表​,​为​保​证​系​统​的​实​时​性​和​稳​定​性​,​建​立​了​一​套​完​整​的​异​常​处​理​机​制​。​A​R​M​T​T​D​M​I​内​核​微​处​理​器​支​持种​处​理​器​模​式​,​有种​异​常​模​式​:​快​中​断​、​中​断​、​管​理​、​中​止​和​未​定​义​模​式​。​只​要​正​常​的​程​序​流​程​被​打​断​,​处​理​器​就​进​入​异​常​模​式​,​并​由​固​定​人​口​地​址​转​入​相​应​模​式​,​如​表所​列​。
试读已结束,如果需要继续阅读或下载,敬请购买
把文档贴到Blog、BBS或个人站等:
普通尺寸(450*500pix)
较大尺寸(630*500pix)
你可能喜欢
同期刊文献2803人阅读
寄存器和工作模式:7种工作模式:fiq/irq/abt/und/sys/usr/svc。通过"MSR cpsr_c,#0xdx"切换。上电时进入svc模式。svc和usr的区别是:svc可以通过"MSR cpsr_c,#0xdx"自由切换到其它任何模式,但是usr不可以。各模式下有自己的堆栈。要在程序启动后依次进入各个模式分别设置自己的堆栈,最后进入usr模式。好多个寄存器:r0 - r7 (a1 - a4 / v1 - v4),r15(pc) 在所有模式下都可见。r8(v5),r9(sb,v6),r10(sl,v7),r11(fp,v8),r12(ip) fiq模式下有一组独立的映射。r13(sp)/R14(lr) 在usr和sys模式下用同一组映射,其它模式下各有自己的映射。cpsr在所有模式下可见。spsr在usr和sys模式下没有映射。cpsr是一个最特殊的寄存器,结构如下:31 30 29 28 27~8 7 6 5 4 3 2 1 0N Z C V 保留 I F T M4 M3 M2 M1 M0其中,N/Z/C/V分别为负/零/进位/溢出的标志位。在所有模式下都可以进行读操作。I/F为中断/快中断禁止位,M4~M0是工作模式控制位,它们在USR模式下都不可操作。T为Thum/ARM模式位,在所有模式下不可直接操作,否则会天下大乱,预取址错误中断可以捕获这种乱局。只能用BX指令进行Thum/ARM的状态切换。总之,USR模式很不方便。在该模式下只可以通过软中断控制I/F位。cpsr只能够用MSR/MRS指令来操作。各工作模式下的spsr: 在由突发事件引起的模式切换发生时,新模式的spsr自动保存cpsr的值,以备该模式退出时还原cpsr。在程序的控制下进入某模式时,cpsr不会自动保存到相应的spsr。Prefetch Abort和Data Abort模式:Prefetch Abort通常会发生在自修改指令之后。而Data Abort发生于向无效内存中取操作数时,通常是数据指针越过边界了。如果在scatter文件中不指定边界,若编译时内存分配超过了实际物理内存,一定会有Data Abort或Prefetch Abort发生。对特殊功能寄存器的操作:通常都有两个寄存器操作同一个特殊功能。一个是负责置位,另一个是负责清除。如VICIntEnable和VICIntEnClr, IOxSET和IOxCLR等。这样就使得单独操作某一位或某几位变得非常容易,如:IO0SET = 0x;IO0CLR = 0x等,只变动特定的位,而不影响其他位。当然也可以用IO0PIN = 0x直接设置所有的位。--------------------------------------------------------------------------------存储器映射:0-1G(0x - 0x3fff,ffff): 片内Flash.1-2G(0x - 0x7fff,ffff): 片内RAM.2-3.5G(0x - 0xbfff,ffff - 0xdfff,ffff): 片外存储器。3.5G - 3.75G(0xe000,0000 - 0xefff,ffff): VPB外设。3.75G - 4G(0xf000,0000 - 0xffff,ffff): AHB外设。虽然ARM7的寻址空间为4G,但是LPC2200系列只提供A0~A23总共16M的地址。片选信号CS0 - CS3是A24和A25的译码输出,将片外存储区0x - 0x83ff,ffff划分为bank0 - bank3,共16M*4=64M. 这4个bank可以被分别配置为8/16/32位总线宽度。复位时,bank0的总线宽度由Boot1:0引脚决定, bank1为32位,bank2为16位,bank3为8位。字节定位信号(BLS0 - BLS3)协调总线宽度和外存芯片数据线宽度。当Memory由&字节宽度器件&(如62256)或者&未按照字节区分的多字节器件&组成时,应将RBLE设置为"0"。此时,读访问时EMC将BLS0~BLS3拉高。当Memory由&含有字节选择输入的16位或32位器件&组成时,应将RBLE设置为"1"。此时,读访问时EMC将BLS0~BLS3拉低。所以,当Memory由62256组成时,由于不需要&片内字节选择输入&,故令RBLE = '0',则BLS0~BLS3只会与nWR同步,可以代替nWR使用。但是,当Memory由IS61LV25616AL组成时,由于该芯片有"nLB"和"nUB"控制低/高8位的输入,故令RBLE = '1',则BLS0~BLS3与nRD和nWR都会同步,此时,不可以使用BLS0~BLS3代替nWR信号。地址数据总线:D0 - D31, A0 - A23, OE, WE, CS0 - CS3, BLS0 - BLS3启动后由P2.7/P2.6控制引导方式,然后由程序设置MEMMAP决定中断向量的映射。BCFG0 - BCFG3控制读写延时和总线宽度。注意复位后的默认值。PINSEL2控制引脚功能。Boot BlockLPC的BootBlock被固化在最高的Flash块中,运行时被映射到0x7FFF,E000 - 0x7FFFF,FFFF的区域。而LPC2210没有片内Flash,但它有8K片内ROM存储了BootBlock,也被映射到0x7FFF,E000处。--------------------------------------------------------------------------------VPB只是ARM内部使用的总线,它通过桥与AHB总线连接,对用户透明。所以,不必考虑它的存在,只要知道0xe000 - 0xffff,ffff 是外设控制器的地址就可以了。--------------------------------------------------------------------------------VIC:ARM有19个中断源,为其分配了0 - 18号VIC通道。向量控制寄存器VICVectCntl0-15记录了各个通道号及其使能位。当中断发生时,VICVectAddr0-15中的一个值会被copy到VICVectAddr.如果是非向量中断则VICdefaultAddr被copy到VICVectAddr.程序跳转到VICVectorAddr指向的地址。中断返回时,写0x00到VICVectAddr.非向量中断是指那些虽然已经打开(允许),但是没有在相应的VICVectorCntl0~15和VICVectorAddr0~15中设置的中断。关于中断设置:1、首先,硬复位后所有的Special Function Registor都有默认值。不必考虑设置的顺序问题。可以先设置好中断,再开通模块功能。2、软中断(SWI)与非向量中断不同,它的入口是0x。进入软中断后,系统变为管理模式。而非向量中断入口是0x。它引导系统进入fiq/irq模式。3、VIC设置实例:& & VICIntSelect = 0x;& & //所有中断都是IRQ& & VICVectCntl0 = 0x20 | 15;& & //EINT1为向量中断,使用Slot0& & VICVectAddr0 = (uint32)EINT1_E& & //EINT1中断地址& & VICDefVectAddr = (uint32)Default_E& & //非向量中断地址& & VICIntEnable = 0x;& & //使能EINT1和EINT2& & 由于在管理向量中断的VICVectCntl0~15和VICVectAddr0~15中只设置了EINT1,故EINT2中断发生时,要进入非向量中断处理程序Default_Entry。关于优先级:在调试C语言的多中断程序时,在中断中设断点,调了几个循环就全乱了。开始时怀疑编译器有问题,后来发现是Debugger不够好。测试如下:1、修改C Compiler的优化级别为最低。重新编译。2、令Timer0定时0.25秒中断,在中断中将Test++。& &令EINT3(外部RTC)1秒中断,在中断中用LCD显示Test的值并将一个LED取反。然后再用软件延时,占据CPU0.9秒或0.5秒后才退出中断。3、令Timer0的优先级小于EINT3。LED为1秒断续,LCD显示的Test值一秒加一。4、令Timer0的优先级大于EINT3。LED为1秒断续,LCD显示的Test值一秒加一或加二或加四。结论:Timer0中Test加一/加二/加四是在EINT3退出后的间隙中完成的。所以,IRQ中可能没有传说中的优先级机制。关于Spurious Interrupts:见的介绍。其中Solution1、2、3皆可行。当然,最好的办法是不要老是关中断。在18App的主循环中不断关闭/开启UART的中断以读取其缓冲区的长度及数据,出现以下现象:程序经常走进VICDefaultAddress!解释:当UART中断产生时,Core latches the IRQ status,此时,UART的中断被关闭。然后,Core loads IRQ Address from VIC. the VIC will not be able to clearly identify the interrupt that generated the interrupt request, and as a result the VIC will return the default interrupt VICDefVectAddr.--------------------------------------------------------------------------------关于周立功EasyJTAG设置:计算机并口要设为SPP模式。弹出Fatal Axd Error时,点击Connect mode...选择ATTACH...然后Restart即可。--------------------------------------------------------------------------------编译和调试:Project-&Remove Object Code...删除当前运行代码,然后可以重新编译。Axd Debugger运行时会产生C:/documents and settings/username/default-1-2-0-0.sec.如果在打开Axd Debugger时不能自动调入Image, 可以删除此文件,重新打开Axd Debugger, 然后调入Image即可。单步执行时对特殊功能寄存器的监视:要监视Timer0寄存器组,从0xE000,4000开始。打开"Processor View"-&"Memory"定位在0xE0004000。刚开始运行时监测结果正常,几个循环后,0xEPR)开始不断变化,而这个寄存器除了初始化时,不应该变化的。本应该变化的寄存器如0xETC)反而不变了。于是打开"Processor Views"-&"Watch",在里面加入 *((unsigned long*)0xE0004000)至 *((unsigned long*)0xE000403C)进行观察。发现Watch窗口的内容与Memory中的不同,似乎是Memory中的内容与其对应的地址产生了4个字节的错位。因为Memory中0xE000400C的内容总是与Watch中0xE0004008的内容相近,两者的差别大概是JTAG两次读RAM的时间差。另外,RAM的0xE000401C与Watch中0xE0004018内容相同。所以,Watch窗口的内容是正确的。Debug:Axd的Disassembly窗口:有单三角箭头的两个按钮,用于在小范围内(页内)滚动汇编程序。也有双三角箭头的两个按钮,用于在整个汇编程序的范围内移动。Axd的"Low level symbles"窗口可用于观察各变量的地址,此窗口在辅助阅读Disassembly时有用。--------------------------------------------------------------------------------分散加载描述文件.scf的设置Metrowerks Code Warrior V1.2的"Edit-&Debug In ExRAM Settings",然后在"Linker-&ARM Linker"的Output页中,选中Scatter选项。在Scatter的编辑框中选择写好的.scf文件。(Scatter-Loading description file).简单应用时可以不写.scf文件。而在"Output"页中选择"Simple".然后填写"RO Base"和"RW Base"的起始地址。在"Lay Out"页中,填写Object/Symble: Startup.o, Section: Start.编写启动文件:Startup.s.在"Option"页里的"Image Entry Point"填入起始地址。--------------------------------------------------------------------------------Scatter-Load Description File的结构:".scf"文件中的"+RW"对应".s"源文件中的"READWRITE".".scf"文件中的"+ZI"对应".s"源文件中的"NOINIT".".scf"文件中的"+RO"对应".s"源文件中的"READONLY".在".s"源文件中有:AREA area_name CODE/DATA,READONLY/NOINIT/READWRITEEND".scf"的例子:内容   注解ROM_LOAD 0x{   Name of Load Region, Start Address for Load Region and Maximum size of Load Region(省略了)  ROM_EXEC 0xx20000{ 片外存储区,从0x开始,最多0x20000字节。  Startup.o(Vector,+First) Startup模块的Vector段放在最前面。注1  *(+RO) 其他所有模块中的所有代码和只读的数据放在这里。  }    IRAM 0xx{ 片内RAM区,从0x开始,最多0x4000字节  Startup.o(MyStacks,+first) 指定Startup.o中MyStacks放在最前面。  Startup.o(+RW,+ZI) Startup.o中的其他+RW/+ZI段。注1  os_cpu_a.o(+RW,+ZI)    }    STACKS 0x UNINIT{ 片内16K RAM的顶端,存放不需要被"C library"初始化的段。  Stack.o(+ZI) 注2  }    ERAM 0x{    *(+RW,+ZI)    }    HEAP +0 UNINIT{ "+0"表示接着上一段"ERAM"的结尾,继续安排存储区。  Heap.o(+ZI) 注3  }  }    下面是在scf文件中引用过的源文件示意:"Startup.s"&&code 32&&area Vectors,CODE,READONLY&&entry&&...&&end 注1:在"Startup.o"里面会生成名为"Vectors"的段,段的属性为"READONLY""Stack.s"&&area Stacks, DATA, NOINIT&&export StackUsrStackUsr&&SPACE 1&&end 注2: 在"Stack.o"里面会生成名为"Stacks"的段,段的属性为"NOINIT",该属性对应scf文件中的"+ZI". 该段不需要初始化或者可以被初始化为"0"."Heap.s"&&area Heap,DATA,NOINIT&&export bottom_of_heapbottom_of_heap&&SPACE 1&&end 注3: "Heap.o"里面名为"Heap"的段。在Scatter文件中最好每一个Region都加一个Maximum参数,这样当编译时如果实际使用的空间大于Maximum Size,会有Error:16220E: Excution region xxx size (xxx bytes) exceeds limit (xx bytes)。如果地址有重复,会有Error: 16221E: Excution region xxx overlaps with excution region xxx。前一个Region的首地址 + Maximum & 后一个Region的首地址时不一定有Error。只有当一分配的内存出现覆盖时才会有Error。Region的"UNINIT"之类的参数要放在"Maximum size"参数之前。在一个Region中,RAM的分配不是按照罗列的顺序来的。要想让汇编中使用的变量有固定的位置,可以把所有汇编文件产生的".o"放在同一个Region中。如:IRAM1 0x{&&startup.o(+RW,+ZI)&&ASMSourceCode1.o(+RW,+ZI)&&ASMSourceCode2.o(+RW,+ZI)}IRAM2 +0{&&CSourceCode1.o(+RW,+ZI)&&CSourceCode2.o(+RW,+ZI)}这样,所有汇编中定义的变量地址就相对集中了。如果只有一个汇编文件如startup.s,也可以这样:IRAM 0xx1000{&&startup.o (Mystack,+first)&&*(+RW,+ZI)}用一个"+first"强行将startup.s中的Mystack放在0x位置。在"Edit -& DebugRel Settings...-&ARM Linker"中选中"Image map"。编译后在Error & Warnings窗口会显示出详细的内存分配情况。如果在"List file name"中指定一个输出文件名,该祥单会直接存在制定文件中以供多次研究。--------------------------------------------------------------------------------关于JTAG接口:P1.20/TRACESYNC应该加上拉电阻以禁止TRACE功能。PINSEL2一定要在程序开始时初始化一下。LPC2210JTAG注  1,2/VDD3.3V  P1.31/nTRST, input 3/nTRST, output EasyJTAG中有上拉电阻。P1.28/TDI, input 5/TDI, output EasyJTAG中有上拉电阻。P1.30/TMS, input 7/TMS,output EasyJTAG中有上拉电阻。P1.29/TCK, input/output 9/TCK, input/output EasyJTAG中有上拉电阻。P1.26/RTCK, input 11/RTCK, output P1.26外接下拉电阻。P1.26有内部上拉电阻,故测量时该引脚会呈现高电平。但是在复位时,它的上拉电阻不起作用,只有外部的下拉电阻起作用,P1.26 = 0V, 所以上电后PINSEL2的D3~D0会是0x04(B0100),JTAG有效。若将P1.26接到3.3V再复位,此时PINSEL2的D3~D0将会是0x00,JTAG无效。P1.27/TDO, output 13/TDO, input EasyJTAG中有上拉电阻。nRESET, input 15/nRST, output EasyJTAG中有上拉电阻。  4,6,8,10,12,14,16,18,20/GND    17,19/NC  G18控制板采用LPC2114,每次运行Axd都不会正确调入程序。原因如下:有一次是因为已经有一个Axd在运行了,打开第二个Axd, 当然不会正确调入程序。还有一次是重新编译了一下,就好了。以上两次都不奇怪,奇怪的是下面几次:在"Config Target -& Config -& Easy JTag Setup"随便点两下"Halt Mode"中的选项,然后一路点击"OK",会出现"Reload the last Image?",点击"Yes"。有时会有正确的程序被调入,但有时候不成功。要检验是不是已经成功调入了,只要按下"Ctrl-D"显示Disassembly窗口,即可看到芯片中的程序是否正确。在"Option -& Config Interface -& Session File -& Session file Options"中选择"Reload Images",之后每次启动Axd都会提示"The processor ARM_1 already has image(s) loaded. Continue the operation will replace the currently loaded images(s).... Do you wish to continue?" 选择"Yes", 有时候也可以成功调入程序。当然,在"Easy JTag Setup -& Aux Option"中要选中"Erase Flash when need".固化的程序中有禁止JTag调试端口的语句(操作PINSEL2的语句),连不上时用LPC2000 Flash Utility擦除了Flash。偶尔可行。注意使用LPC2000 Flash Utility时要先将电路复位,再点"OK".当然最根本的解决办法是将计算机并口设置为"EPP"模式。其他地方都按照"Default"就可以了。--------------------------------------------------------------------------------有效用户代码:ARM把&向量表所有32位数据累加和为0&作为有效用户代码的条件,只适用于使用片内程序存储器的时候,片外程序存储器无此限制。C语言程序通常需要一段用于初始化的汇编代码,通常存储为"Startup.s",它实现的任务通常是:1、做好中断向量表2、初始化外部总线控制器/堆栈/目标板基本模块。3、给库函数使用的"__user_inital_stackheap"。4、除数为零时的死循环"__rt_div0: B __rt_div0"。5、支持加密功能的语句。6、定义堆栈空间:AREA MyStacks, DATA,NOINIT,ALIGN = 2要定义栈的起始地址:IrqStackSpace SPACE ...和栈的头部:StackIrq DCD IrqStackSpace + Length*4。因为栈是向下生长的。与目标板有关的初始化程序可以放在一个名为"Target.c"的文件里。1、定义中断处理入口:void IRQ_Exception(void), void FIQ_Exception(void), void Timer0_Exception(void)。2、向量中断控制器初始化。3、remap,系统时钟,实时时钟,存储器加速。--------------------------------------------------------------------------------C语言中的延时:__asm{&&&&}即可。关注C编译器:"=="的优先级确实比"&"的高,所以,凡牵扯到逻辑的东西,用"()"确认优先级,以避免出现低级错误。--------------------------------------------------------------------------------对定时器的操作:void Timer0Init(uint8 VICSlot, uint32 fdiv){&&T0PR = 0; //Prescaling = 0&&T0PC = 0; //Prescalar Counter&&T0TC = 0; //T0 Counter&&T0MR0 = Fpclk / //计数周期&&T0MCR = 0x03;&&//计数达到T0MR0则置位中断,计数器复位并继续运行。&&T0CCR = 0x00;&&//不用捕获模式&&T0TR = 0 //清中断&&T0TCR = 0x01;&&//运行&&if(VICSlot &= 15){& & *((uint32*)(&VICVectAddr0 + VICSlot)) = (uint32)Timer0_E& & *((uint32*)(&VICVectCntl0 + VICSlot)) = 0x20 | 0x04;& & VICIntEnable = 1 && 0x04;&&}}注意:1、"*((uint32*)(&VICVectAddr0 + VICSlot)) = ..."中,&VICVectAddr0作为基址,VICSlot作为偏移量。由于前面已经有(uint32*)声明这是一个指向uint32的指针,故偏移量每变化一个数字代表地址变化了4个字节,在基址与偏移量相加的时候,系统自动将VICSlot乘以4。如果程序中写成"... + 4 * VICSlot"就错了。2、一定要用"Fpclk / fdiv"设置,以延时1/fdiv秒。该参数不可以以uS为单位。若"Fpclk * us / 1000000"在计算中会乘法溢出,不易避免,又无警告,故不可用。--------------------------------------------------------------------------------对I2C占空比的设置:I2SCLH = (Fpclk / fi2c + 1) / 2;I2SCLL = (Fpclk / fi2c) / 2;妙哉!无论"Fpclk / fi2c"是奇是偶,单方面的"Fpclk / fi2c + 1"使得I2C总周期"Fpclk / fi2c = I2SCLH + I2SCLL"在方法上没有误差。I2C必须工作在中断模式。因为:"When the "SI" flag is reset, no serial interrupt is requested, and there is no stretching of the serial clock on the SCL line."I2C的资料在--------------------------------------------------------------------------------宏的应用:在片内外设如I2C,UART,T0,T1,SPI的设置过程中,都需要根据Fpclk计算出一些设定值。我讨厌用ARM做除法,所以就用宏来实现,除法在编译时就可以完成。首先,所有片内外设的初始化程序都名为:"void _xxxInit();"。之所以在正式函数名之前加一个"_",是为了与宏区别开,不至于误写函数。因为宏的名字与函数名相同,只是全部大写,并且前面没有"_"。如:#define TIMER0INIT(VICSlot,ms) _Timer0Init(VICSlot,Fpclk/100*ms/10);void _Timer0Init(uint8 VICSlot,uint32 ClockCycle);在函数中,直接"T0MR0 = ClockCycle"即可。注意宏里面的表达式,不可写成"Fpclk*ms/1000",因为如果这样写,当mS太大时,比如mS=1000, Fpclk*mS=()*CB8000,算到这一步,编译器认为是溢出(它把计算结果看作是有符号数),只要有溢出的警告出现,设置就不正确。也不可以先做除法,以防止吃掉精度,使计算结果为"0"而令定时器死掉。总之,既要保证计算精度,又不可以出现溢出警告。--------------------------------------------------------------------------------关于C编译器使用的堆栈设置:1、在Startup.s中有一句:&&MSR CPSR_C,#0x5f& & //系统模式&&LDR SP, =UsrStack&&//用户栈2、在Scatter文件中,有&&STACKS 0x UNINT&&{& & UsrStack.o(+ZI)&&}3、在UsrStack.s中有&&AREA Stacks, DATA, NOINT&&EXPORT UsrStack&&UsrStack SPACE 1&&END定义一个UsrStack,大小都无所谓,把它放在可用物理内存的最顶端。C编译器在编译子程序调用时,会将要保护的寄存器压栈,如:&&stmfd r13!,{r3-r7,r14}其中,r13的别名是SP。这是一个满递减堆栈。即SP指向的单元内的数据是有效的,入栈时先减SP再存数据。--------------------------------------------------------------------------------C编译器的全局变量和局部变量:全局变量从Scatter文件规定的起始地址向地址增加的方向生长。局部变量从堆栈中规划,向地址减小的方向生长。实验如下:1、在".c"中定义全局变量:&&uint8 ucData2[17]="__/__ hh:mm:ss";2、在main()函数中定义局部变量:&&uint8 ucdata1[17]="abcdefghijklmnop";3、运行程序,至"void main(){"处停下。观察0x处为"__/__ hh:mm:ss"。堆栈指针SP(r13)=0x。4、观察地址0x40003c00处,没有蛛丝马迹。按"Step In"单步执行,指针停在"uint8 ucdata1[17]="abcdefghijklmnop";"处。 SP变为0x40003FC8。5、再按"Step In"单步执行,进入Disassembly窗口。当前程序标号为"__rt_memcpy",应该是初始化局部变量的。6、按"Step Out"退出Disassembly窗口。0x40003FCC~0x40003FDB被初始化为"abcdefghijklmnop"。&&此时,SP(r13)仍旧为0x40003FC8,与在第4步时的内容相比,没有变化。说明在刚刚进入"void main()"以后,即在第3、4步中间,局部变量的地址就已经分配好了。在安排全局变量的时候,若某一模块有被初始化的需求,则该模块放在前面,Scatter文件中的"+first"被移到所有有初始值得变量后面。"first"只是没有初始化要求的数据块的"first"。--------------------------------------------------------------------------------建立结构:typedef struct {&&uint16 B&&uint16 T&&uint16 MaxL&&unsigned char* P} FIFOCONTROL;以支持一个FIFO环。在UART中断中向里面添加数据。在主循环里读出FIFO的长度及里面的数据。static uint16 FIFOGetLength(FIFOCONTROL* pFifo){&&if(pFifo-&Bottom &= pFifo-&Top)& & return (pFifo-&Top - pFifo-&Bottom);&&else& & return (pFifo-&Top + pFifo-&MaxLength - pFifo-&Bottom);}这段程序看起来很简单,但是,如果在"if"和"return"之间被UART中断,并且恰好是在pFifo-&Top越过pFifo-&MaxLength时,返回的结果就错了,导致访问到非法地址,而进入Data aboart。解决:不要直接用指针指向的单元作判断和计算。修改如下:static uint16 FIFOGetLength(FIFOCONTROL* pFifo){&&uint16 m,n,r;&&m = pFifo-&B&&n = pFifo-&T&&if(m &= n)& & r = n -&&else& & r = n + pFifo-&MaxLength -&&}只要把临界区的内容倒入m、n中就大吉了。--------------------------------------------------------------------------------莫名其妙:在主循环前面加上初始化的内容如下:&&SPI0ReadWrite(ucData,1);&&ucIOStatus[0] = ucData[0];&&ucIOCurrent[0] = ucData[0];&&ucIOChange[0] = 0;每次运行都会进入SWIS改为:&&m = ucData[0];&&ucIOStatus[0] =&&ucIOCurrent[0] =一切正常,未详查原因。其中,ucIOStatus[]、ucIOCurrent[]和ucIOChange[]虽然写成了数组的样式,但是他们都只包含一个元素,即数组长度是1,不知是否有关系
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:38994次
排名:千里之外
原创:25篇
转载:21篇
(2)(1)(2)(1)(1)(19)(3)(1)(3)(1)(13)

我要回帖

更多关于 lpc2200 spi驱动 的文章

 

随机推荐