1、在调试“E:\htwang\smart2200v201\ARM嵌入式系统实验教程(二)\开发板出厂编程程序\液晶显示程序\LCM_Disp”的程序时,想使用外部RAM进行仿真调试,在将ADS1.2中的“DebugInExram Settings…->Arm Linker -> Output -> Equivalent Command Line”的“-info totals -entry 0x8100000 -scatter .\src\mem_b.scf”改为“-info totals -entry 0x80000000 -scatter .\src\mem_b.scf”时,编译时总是出现错误信息“Error: L6206E: Entry point(0x80000000) lies outside the images”,经梁工(宝琼)提示:“这是由于程序空间超出范围,需要改一个参数。”
打开关于外部RAM调试的分散加载文件“mem_b.scf”发现所有的程序调试地址都是指向0x81000000的Flash地址空间,而不是0x80000000的RAM地址空间(此时硬件电路板上的短路片RAM接CS0、Flash接 CS1),后把0x81******全部改为0x80******,编译调试都正常。
2、不正常现象:在调试“SmartARM2200 V2.02”实验箱时,每次实验箱断电或实验箱上复位按键后,H-Flash的Load操作都要重新执行一遍(或者简单一点:只要在H-Flash -> Programming -> Check 按钮上点击一下也可以),否则下载程序后实验箱运行不了。
(先是在选用DebugInExram出现这种情况,后选用RelOutChip则不会出现这种情况。)
<2008-9-12> 另外,每次重新启动H-JTAG和H-Flash后,都要将H-Flash重新设一遍。
3、 现象:在调试GB_Disp工程时,程序无法正常运行。
分析:当调试的程序中包含中断时,分散加载文件“mem_*.scf”的“IRAM ”项设置不能从0x40000000开始,而应该从0x40000040开始(给中断向量留下空间),否则程序无法调试。(先是在选用RelOutChip出现这种情况,后选用DebugInExram也出现这种情况。)
< 2008-9-12 htwang注: 上面的解释并不正确,因为在调试其他中断实验的过程中,配置文件“mem_*.scf”的“IRAM ”项设置成从0x40000000开始也可以正常运行。(估计可能是存储器映射的问题)
打开GB_Disp工程“target.c”文件,果然发现在函数“void TargetResetInit(void)”中将存储器映射寄存器初始化成“MEMMAP = 0x2”,这是选用的用户RAM模式,中断向量也从静态RAM重新映射。如果想映射到用户外部存储器模式,应该改为“MEMMAP = 0x3”(见《ARM嵌入式系统基础教程》P166 或《****ARM7—LPC2200》P119)。按此方式更改后,实际调试也正常。
>
(2008-9-12)结论:要么把该工程文件 “mem_bscf” 中的“IRAM ”项改成从0x40000040开始;要么把该工程文件“target.c”中的存储器映射初始化为“MEMMAP = 0x3”。
4、在调试中断程序时,如果使用IRQ.S中的汇编宏定义程序和“IRQ_Eint3_Handler HANDLER IRQ_Eint3”代替原来的C语言函数中断方式(当然同时将代码“VICVectAddr0 = (uint32)IRQ_Eint3;”改为“VICVectAddr0 = (uint32)IRQ_Eint3_Handler; ”),则应将C语言中断函数 “void __irq IRQ_Eint3(void)”改写成“void IRQ_Eint3(void)”。
否则调试是出现的情况就是程序在“IRQ_Eint3_Handler HANDLER IRQ_Eint3”和中断函数“void __irq IRQ_Eint3(void){}”里面反复执行,再也退不出来。
2008-9-12 调试“SmartARM2200 V2.02实验箱”心得:
5、现象:在自己编写定时器中断程序时,如果自己用工程模板“ARM Executable Image for lpc2200”建立工程并编写中断程序后,调试过程中总是不能进入中断,但是用定时中断的事例程序可以进入。
原因:经将自己建立的模板工程文件中的“Startup.s”文件和事例程序中的比较,发现在模板工程的“Startup.s”文件中的堆栈初始化代码“InitStack …”中有一行语句为:
;设置系统模式堆栈
MSR CPSR_c, #0xdf
LDR SP, =StackUsr
这就将IRQ和FIQ都禁止了,需要将“MSR CPSR_c, #0xdf”改为“MSR CPSR_c, #0x5f”来打开IRQ中断才行。
6、现象:用C语言编写中断函数时,如void __irq Timer0Int(void){ },该中断函数必须放在主函数main()的上方,否则编译时会出现错误(因为主函数需要调用语句“VICVectAddr0 = (uint32)Timer0Int;”):
1)Error: (Serious) C2933E: type disagreement for “Timer0Int”
2) Error: C2456E: undeclared name, inventing ‘extern int Timer0Int’
解决方法:在主函数前面加上声明“void __irq Timer0Int(void);”(ZLG李工),此时编译应该不会再出现上述的问题,但如果此时Debug运行时不正常,需在ADS1.2(编程软件)执行操作“Project -> Remove Object Code… ”后,再重新编译调试。
如果把C语言编写的中断函数放到其他文件中,也是类似的处理方法,如:“extern void __irq Timer0Int(void);”
7、在ADS软件中int类型占用4个字节的空间。
8、ALIGN=2 ,即定义2的n次幂对齐方式(梅工(程宇))。(见ARM指令集ARM_zhiling.pdf)
9、SvcStackSpace SPACE SVC_STACK_LEGTH * 4; 其中的SPACE为字节空间定义(梅工(程宇)),并用0对之进行初始化。(见ARM指令集ARM_zhiling.pdf)
10、要想看到所有文件(函数)对FLASH和RAM的使用情况,在编译选项设置->ARM Linker -> Listings -> Listings的“Image map”和“Symbols”前面的复选框选中,编译后即可输出想要的详细信息(梅工(程宇))。
11、实验箱上的ZLG7290芯片由于内部键盘处理程序没有去抖动和防连击处理,所以用起来不太好用。(据说ZLG7290芯片只是ZLG用一款单片机写了软件贴了个商标)
2008-9-16 调试“SmartARM2200 V2.02实验箱”心得:
12、中断使能寄存器VICVectEnable写入1,对应通道的中断使能;写入0,无效。如指令:
VICIntEnable = 1 << 6;
VICIntEnable = 1 << 4;
指令这两条指令之后,通道6和通道4都被中断使能。
(课本《****ARM7--LPC2200》的P164有详细说明)
13、在任务Task定义的局部变量与定义的静态局部变量功能等同,因为任务不可能返回,只能被中断(大部分是定时中断,也可能是其他中断)所打断,这时中断会保存相应的现场。(自我理解,没有看到相关资料上如此解释)
14、用typedef定义的结构体不能多次用#include 包含,否则会出现错误:
Error:(Serious) C2930E: duplicate definition of ‘ ***’
<2008-9-16 htwang注:上述结论并不正确,出现这种情况是因为一个有typedef的头文件在同一个文件中include包含了两次。
>
2008-9-17 调试“SmartARM2200 V2.02实验箱”心得:
15、因为任务创建成功后OSTaskCreate()即进行任务的调度OS_Sched(),因而与此相关的事件创建(如消息邮箱)程序要放在先创建的任务中,而不是放在即将创建的高优先级任务中。
<2008-9-17 htwang注:上述结论不正确,因为任务创建后并不会马上运行,它创建后的切换操作总是会切换到最高优先级的任务运行,而一般我们都是用高优先级的任务进行所有低优先级任务的创建,因此任务仍然会返回起始任务继续创建其它任务。所以与此相关的事件创建(如消息邮箱)程序必须要放在相关的即将创建的高优先级任务中。
>
16、现象:在使用消息邮箱进行工程“E:\htwang\uCOS_Homework\uCOS_Homework”调试时,发现消息邮箱的指针DispMbox总是被不正常修改(因此程序也就不能正常运行)。
检查调试:经反复检查调试,发现在一个任务中使用了一个100字节的字符数组,而给这个任务分配的堆栈长度只有64个字节,分析应该是由于堆栈溢出造成的上述现象。于是把该任务的堆栈长度分配为256个字节,不正常现象消失。
17、在调液晶显示程序时,液晶显示速率非常慢,经查是由于uC/OS II工程模板的Startup.s文件中的总线速率配置太慢。原值为:
;IDCY = 0x0f(最大值), WST1 = 0x1f(最大值), WST2=0x1f(最大值)
;RBLE=1(字节选择有效),MW=1(16位宽总线)
LDR R0, =BCFG0
LDR R1, =0x1000ffef
STR R1, [R0]
;IDCY = 0x0f(最大值), WST1 = 0x1f(最大值), WST2=0x1f(最大值)
;RBLE=1(字节选择有效),MW=1(16位宽总线)
LDR R0, =BCFG1
LDR R1, =0x1000ffef
STR R1, [R0]
;IDCY = 0x0f(最大值), WST1 = 0x1f(最大值), WST2=0x1f(最大值)
;RBLE=1(字节选择有效),MW=2(32位宽总线)
; LDR R0, =BCFG2
; LDR R1, =0x2000ffef
; STR R1, [R0]
;IDCY = 0x0f(最大值), WST1 = 0x1f(最大值), WST2=0x1f(最大值)
;RBLE=1(字节选择有效),MW=2(32位宽总线)
; LDR R0, =BCFG3
; LDR R1, =0x2000ffef
; STR R1, [R0]
修改后的总线配置为:
; 定义总线速度控制字
BCFG_DEF EQU 0x10000400
IDCY EQU (0x00<<0)
WST1 EQU (0x01<<5)
WST2 EQU (0x01<<11)
BCFG3_SET EQU (BCFG_DEF | IDCY | WST1 | WST2)
IDCYFS EQU (0x01<<0)
WST1FS EQU (0x03<<5)
WST2FS EQU (0x03<<11)
BCFG_FS EQU (BCFG_DEF | IDCYFS | WST1FS | WST2FS)
LDR R0, =BCFG0
LDR R1, =BCFG_FS
STR R1, [R0]
LDR R0, =BCFG1
LDR R1, =BCFG_FS
STR R1, [R0]
LDR R0, =BCFG2
LDR R1, =0x1000ffef
STR R1, [R0]
LDR R0, =BCFG3
LDR R1, =BCFG3_SET
STR R1, [R0]
分析:由于液晶接在CS3,而CS3的总线配置在uC/OS II工程模板的Startup.s文件中被分号所屏蔽,所以其值为默认值(最大延时)。把有关CS3的屏蔽去掉,也应该能加快液晶显示速度。
结论:经实际调试,把uC/OS II工程模板的Startup.s文件中有关CS3的总线配置屏蔽去掉并不能正常进行液晶显示,因为原值为配置的32位总线宽度(见上面程序中后加的注释分析),原总线类型配置值与液晶不匹配,必须要进行修改。
2008-09-19调试“E:\htwang\uCOS_Homework2”目录下的工程心得:
18、互斥信号量是对共享资源的独占,最好一次使用完必须立即释放。如果不想一次使用完就释放(需要该共享资源使用一段时间或好几次循环),那么在另一个任务中对共享资源的请求当然可以采用OSMutexPend(RTCModifyMutex,0,&err) 的方法,但只需要该任务如果得不到共享资源就不能执行其他操作;如果任务在得不到共享资源的情况下仍然需要执行其他必须的操作,那么用if(OSMutexAccept(RTCModifyMutex,&err))的方法请求互斥信号量是一个很好的选择。
19、信号量发送(包括互斥信号量)没有广播发送的方式,信号量集也没有;只有消息和消息队列有广播发送的方式。
20、为什么在所有软中断和IRQ中断只保存了R0-R3和R12,其他的R4-R11为何没有保存?(见《嵌入式实时操作系统uC/OS-II 原理及应用》的P220)
(2008-9-19 赵永科答)查看一个C语言函数编写的反汇编代码,如果使用了太多的局部变量等,C语言函数会在程序开始部分自动把R4-R11保存起来(不是全部,用到多少保存多少),如:
STMFD r13!,{r4-r11,r14} (其中一个C函数头部的反汇编)
stmfd r13!,{r1-r11,r14} (其中一个C函数头部的反汇编)
stmfd r13!,{r3-r7,r14} (其中一个C函数头部的反汇编)
所以IRQ中断只保存了R0-R3和R12)。
<htwang注:在编译阶段的所有C语言函数里,函数会在开头自动把R4-R11都保存起来,如:STMFD r13!,{r4-r11,r14} (编译阶段其中一个C函数头部的反汇编)
而在调试阶段的所有C语言函数里,函数会在开头自动把R4-R11中用到的变量智能自动保存起来,如:
stmfd r13!,{r1-r11,r14} (调试阶段其中一个C函数头部的反汇编)
stmfd r13!,{r3-r7,r14} (调试阶段其中一个C函数头部的反汇编)
>
2008-09-20调试“E:\htwang\uCOS_Homework3”目录下的工程心得:
21、使用内存分区时,每“一组”数据都要申请一个内存块。(不是每一个数据,存放每一个数据只需把申请到的对应的指针加1就行)
22、在调试“E:\htwang\uCOS_Homework3”目录下的工程时:如果分配AD数据采样任务TaskSamp的优先级大于显示任务TaskDisp的优先级时,当AD数据采样任务TaskSamp中在开始没有延时(如OSTimeDly(1);)程序总会出现预取指中止;但当设置AD数据采样任务TaskSamp的优先级小于显示任务TaskDisp的优先级时,即使没有延时OSTimeDly(1)程序也能运行。不知是什么原因。
经反复检查调试,发现给AD数据采样任务TaskSamp分配的堆栈太小(只有64个字节),当把该任务堆栈大小改为256个字节时,各种情况下调试都很正常。
分析得出:当给任务分配的堆栈空间太小,在堆栈使用溢出后,会占用其他任务的堆栈空间。因此程序就会出现不可预料的结果。
(堆栈分配太小还可能出现的情况,如本调试心得第15条)
2008-09-22调试“E:\htwang\uCOS_Homework3”目录下的工程心得:
23、像程序中的函数“OSTimeDly(OS_TICKS_PER_SEC * 5); //每5s采样一次” (配置头文件中定义:#define OS_TICKS_PER_SEC 200) ,其参数并不需要人工强制类型转换,如“OSTimeDly((uint16)OS_TICKS_PER_SEC * 5);”调试阶段的反汇编会自动将它们算好作为一个常量处理,如下面的实际反汇编:
[0xe3a00ffa] mov r0,#0x3e8 ;OS_TICKS_PER_SEC * 5 =200*5 =1000=0x3e8
[0xebffff4e] bl OSTimeDly
24、创建动态内存分区时“OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)”,需注意:
1)、必须要指向一个具体的二维数组,如“uint8 ADCDataPart[10][100];”即addr不能为空;
2)、每个内存分区的块数必须不能小于2,即nblks >= 2;
3)、每个块的大小必须至少能够放下一个4字节的指针(void *),即blksize >= sizeof(void *);
<htwang注:也就是说每个块有4个字节的空间被指针所用。即如果你定义了100个字节的块空间大小,只能使用96个字节。这样看来在《基于嵌入式实时操作系统的程序设计技术》的P130-P133的例程L8-7出现错误。
>
2008-09-22注:经ZLG梅工(程宇)多方确认:原来的程序没有错误。这个需要将OSMemCreate()、void *OSMemGet(OS_MEM *pmem, INT8U *err)和INT8U OSMemPut(OS_MEM *pmem, void *pblk)三个函数联系起来看。
在OSMemGet()中,总是将指针OSMemFreeList指向下一个未用的空间,这样申请到的块中的所有空间(包括4个字节的指针空间)可以一起使用。原来申请到使用的块的指针空间会在OSM emPut()中恢复。
在OSMemPut()中会把在OSMemGet()中申请到的指针(指向该块的首址)重新建立一个指向下一个块(原OSMemFreeList指向的单元)的指针。
具体请看这3个函数的源代码。
25、对按键的延时去抖和防连击处理。参考了《基于嵌入式实时操作系统的程序设计技术》P163的按键处理例程。
26、(2008-9-23)在使用LPC2000系列ARM的AD转换部件时发现:每个通道在进行AD转换时,第1次采样和第2次采样有较大的误差;而第3次采样又和第1次一样,第4次采样和第2次一样…
如:1994mV,2036mV,1994mV,2036mV…
因此,每次都应对同一个通道采样两次,然后舍弃前一个值。见《基于嵌入式实时操作系统的程序设计技术》P132的AD采样例程。