周立功ARM调试心得

ARM 316浏览

2008-9-11 调试“SmartARM2200 V2.02实验箱”心得:

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”发现所有的程序调试地址都是指向0x81000000Flash地址空间,而不是0x80000000RAM地址空间(此时硬件电路板上的短路片RAMCS0Flash CS1),后把0x81******全部改为0x80******,编译调试都正常。

 

2、不正常现象:在调试“SmartARM2200 V2.02实验箱时,每次实验箱断电或实验箱上复位按键后,H-FlashLoad操作都要重新执行一遍(或者简单一点:只要在H-Flash -> Programming -> Check 按钮上点击一下也可以),否则下载程序后实验箱运行不了。

(先是在选用DebugInExram出现这种情况,后选用RelOutChip则不会出现这种情况。)

       <2008-9-12> 另外,每次重新启动H-JTAGH-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—LPC2200P119)。按此方式更改后,实际调试也正常。

 >

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

       这就将IRQFIQ都禁止了,需要将“MSR     CPSR_c, #0xdf”改为“MSR     CPSR_c, #0x5f”来打开IRQ中断才行。

 

6、现象:用C语言编写中断函数时,如void   __irq Timer0Int(void){   },该中断函数必须放在主函数main()的上方,否则编译时会出现错误(因为主函数需要调用语句“VICVectAddr0 = (uint32)Timer0Int;”):

1Error: (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个字节的空间。

 

8ALIGN=2 ,即定义2n次幂对齐方式(梅工(程宇))。(见ARM指令集ARM_zhiling.pdf

 

9SvcStackSpace      SPACE   SVC_STACK_LEGTH * 4 其中的SPACE为字节空间定义(梅工(程宇)),并用0对之进行初始化。(见ARM指令集ARM_zhiling.pdf

 

10、要想看到所有文件(函数)对FLASHRAM的使用情况,在编译选项设置->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]

分析由于液晶接在CS3CS3的总线配置在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) 的方法,但只需要该任务如果得不到共享资源就不能执行其他操作;如果任务在得不到共享资源的情况下仍然需要执行其他必须的操作,那么用ifOSMutexAccept(RTCModifyMutex,&err))的方法请求互斥信号量是一个很好的选择。

 

19、信号量发送(包括互斥信号量)没有广播发送的方式,信号量集也没有;只有消息和消息队列有广播发送的方式。

 

20、为什么在所有软中断和IRQ中断只保存了R0-R3R12其他的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-R3R12)。

<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  *OSMemGetOS_MEM *pmem, INT8U *err)和INT8U  OSMemPutOS_MEM  *pmem, void *pblk)三个函数联系起来看。

OSMemGet()中,总是将指针OSMemFreeList指向下一个未用的空间,这样申请到的块中的所有空间(包括4个字节的指针空间)可以一起使用。原来申请到使用的块的指针空间会在OSM emPut()中恢复。

OSMemPut()中会把在OSMemGet()中申请到的指针(指向该块的首址)重新建立一个指向下一个块(原OSMemFreeList指向的单元)的指针。

具体请看这3个函数的源代码。

 

25、对按键的延时去抖和防连击处理。参考了《基于嵌入式实时操作系统的程序设计技术》P163的按键处理例程。

 

26、(2008-9-23)在使用LPC2000系列ARMAD转换部件时发现:每个通道在进行AD转换时,第1次采样和第2次采样有较大的误差;而第3次采样又和第1次一样,第4次采样和第2次一样

如:1994mV2036mV1994mV2036mV…

       因此,每次都应对同一个通道采样两次,然后舍弃前一个值。见《基于嵌入式实时操作系统的程序设计技术》P132AD采样例程。