<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采樣例程