不知不覺中就度過三個月的試用期了,邁向第六個月,雖然剛進公司的第一個星期我就想離職了 ,補上從公司看 101 的夕陽照。
從一開始遠在美國的印度主管和同事們,部門在台灣只有我一個工程師,到現在陸陸續續已經有四個同事加入,繼續觀察下去囉,呵。
星期五, 12月 11, 2009
RT3090sta
This patch is coming from 2.6.32-rc8 and I do a few modification to make it backward compatible against the older kernel version(< 2.6.29), don't forget copy the file RT2860STA.dat under /etc/Wireless/RT2860STA/.
rt3090-backward-compatible.patch
RT2860STA.dat
rt3090-backward-compatible.patch
RT2860STA.dat
星期三, 7月 22, 2009
GCC Inline Assembler for ARM
某些時候,即便我們寫的是 C,但是可能會需要直接去透過 assembly 去對硬體(SoC)做一些控制,而這樣混合 C 及 assembly 的寫法其實是比較直觀,更容易懂的。例如整個函式主要是用 C 實作,方便我們可以了解程式實作的邏輯,但是在 critical 或是 C 沒有支援的部份,像關閉 IRQ 或 FIQ 則是透過 assembly 完成。
以下是我在 ucosii 裡實作 critical section 保護方式,這個方式在進入 critical section 前,將 CPSR 的值存到變數 cpu_sr 裡,同時 disable IRQ 及 FIQ,而當離開 critical section 後,則將存放在 cpu_sr 的原 CPSR 值存回 CPSR裡,這是比較複雜的 inline assembly,因為我們會利用到 C 函式裡宣告的變數 cpu_sr,記住底下是一個 #define,在許多 usosii 的 C function 裡都會被使用到
分成四個部份,分別是 arm assembly instruction、output operand list、input operand list 及 clobber list,後面若不需要的話,就留空即可
所有的 assemble instructions 都放在這裡,有些很單純就跟一般的 arm instruction 沒兩樣,有些則是會稍有變化,因為利用到 C 的變數,如果宣告了變數,但在 inline assembly 中需要去存取它們,例如 line 2 及 line 3,此時,就需要 output operand 及 input operand 的搭配使用
[ARM GCC Inline Assembler Paper]
以下是我在 ucosii 裡實作 critical section 保護方式,這個方式在進入 critical section 前,將 CPSR 的值存到變數 cpu_sr 裡,同時 disable IRQ 及 FIQ,而當離開 critical section 後,則將存放在 cpu_sr 的原 CPSR 值存回 CPSR裡,這是比較複雜的 inline assembly,因為我們會利用到 C 函式裡宣告的變數 cpu_sr,記住底下是一個 #define,在許多 usosii 的 C function 裡都會被使用到
#define OS_ENTER_CRITICAL() \
/* \
* Disable both IRQ and FIQ \
*/ \
__asm__ __volatile__( \
"mrs %0, cpsr\n\t" \
"orr r8, %1, #0xC0\n\t" \
"msr cpsr_c, r8\n\t" \
: "=r" (cpu_sr) \
: "r" (cpu_sr) \
: "memory");
#define OS_EXIT_CRITICAL() \
/* \
* Restore the cpsr(IRQ and FIQ) \
*/ \
__asm__ __volatile__( \
"msr cpsr_c, %0\n\t" \
: \
: "r" (cpu_sr) \
: "memory");
分成四個部份,分別是 arm assembly instruction、output operand list、input operand list 及 clobber list,後面若不需要的話,就留空即可
所有的 assemble instructions 都放在這裡,有些很單純就跟一般的 arm instruction 沒兩樣,有些則是會稍有變化,因為利用到 C 的變數,如果宣告了變數,但在 inline assembly 中需要去存取它們,例如 line 2 及 line 3,此時,就需要 output operand 及 input operand 的搭配使用
"mov r0, r0\n\t"output operand list
"mrs %0, cpsr\n\t"
"orr r8, %0, #0xC0\n\t"
"msr cpsr_c, r8\n\t"
: "=r" (cpu_sr)input operand list
: "r" (cpu_sr)你可以把想對 compiler 說的話放在 clobber list 裡,例如 "memory" 是告訴 compiler 記憶體裡的資料是可能被改變的,所以不要去做最佳化,每次要存取該記憶體內容時,都要重新讀取到 register 裡,在 embedded 的世界裡,這是很重要的,也許在某個 ISR 裡某個變數被改變了,如果你直接讀取上次存在 register 的值而不是重新讀取到 register 裡,那,事實上,在 C 裡宣告變數時,可以使用 volatile 去做修飾,都是為了相同的目的。
: "memory");[Download]
[ARM GCC Inline Assembler Paper]
星期一, 7月 13, 2009
星期二, 6月 30, 2009
星期五, 6月 26, 2009
Porting MicroC/OS-II onto Samsung S3C2440 by GNU toolchain
因為 MicroC/OS-II 看起來很不協調,之後將一律使用 ucosii 代替。原始程式碼可以直接到 micrium 的網站下載,我以目前可下載的版本 2.86,再搭配書上 Ch8 Porting uC/OS-II 把移植時需要的函式補齊。
之前曾將 Prex 移植到 GTA02 上,由於 Prex 已經支援 ARM arch,所以當時的工作主要是補上對 device(board) GTA02 的支援,例如 uart driver, timer isr 等,對移植 OS 來說,對於 arch 的支援是指甚麼呢,OS 負責處理的工作有 task management、memory management 、schedule 等,以排程來說,系統同時間有多個 tasks 等著使用 cpu ,OS 選擇優先權最高的 task 執行,這個動作會需要 context-switch,由於不同 arch 有不同的 register 因此這個部份是屬於 arch dependent
另外還有 critical section 的保護,保護 critical section 最簡單的方法就是透過 Disable Interrupt 的方式,而 interrupt 的控制也是和 arch 相關,對 ARM arch 我們可以透過修改 register CPSR 的 I、F bit ,而 Ch8 講的也就是將上述的兩件事補齊。
在一頭鑽進移植的工作之前,先看一下 release note,ucosii 的 release note 寫的很好,很清楚告訴我們新增了哪些檔案,有哪些新的 define、struct,或是哪些函式名稱改變了,這個部份的確幫助我許多。
我把移植 ucosii 分成三個階段,分別是 compile 階段、follow spec 階段、debug 階段。
compile 階段要達到的目的很簡單,先寫個 makefile 讓下載回來的 ucosii 程式碼可以編譯,不會有錯誤訊息,compiler 跟你說少甚麼就補甚麼,少甚麼函式就先補個 dummy function,這邊需要的只是基本判讀錯誤訊息的能力
幾個 dummy function 的例子
一開始就告訴我們需要 app_cfg.h、os_cfg.h、os_cpu.h,用 touch 把這三個檔案生出來,檔案內容都是空的,重點只是先要可以編譯而已,見招拆招。
Recompile,發現這樣的錯誤,想都不用想,我們一定是少了 typedef,由於不同 cpu arch 的 word length 是不一樣的,例如,你不能保證每個 arch 上的 long 都是 4 bytes 吧,所以透過這樣的方式以達到 portable 的目的。
其中 OS_STK 是 stack 的單位,在作 context-switch 時我們需要將 registers 存入 stack 裡,由於 ARM 是 32-bit microprocessor,所以在 os_cpu.h 裡,我補上以下的 typedef:
前面說過,critical section 的保護是 arch dependent 的,所以在 ucosii 的程式碼裏面到處可以看見 OS_ENTER_CRITICAL() 及 OS_EXIT_CRITICAL(),但將這兩個函式定義交給我們實作,一樣先寫兩個 dummy function,記住我們的目的只是先讓編譯的階段可以順利達成,函式的真正實作則是放在 follow-spec 階段
這邊缺少的 function 有 OSDebugInit() OSInitHookBegin() OSInitHookEnd() OSTaskCreateHook() OSTaskDelHook() OSTaskIdleHook() OSTaskStatHook() OSTaskStkInit() OSTaskSwHook() OSTCBInitHook() OSTimeTickHook() OSCtxSw() OSIntCtxSw() OSStartHighRdy() OSTickISR()
至於是要定義在 .h .c 或 .s 檔裡,參照 ch8 porting guide,可以清楚知道這些 dummy function 分別要定義在哪些檔案裡
最後,需要注意的是下面的錯誤訊息,因為 ARM 並不支援除法指令(只有加、減、乘),所以要透過程式支援 modular operator 或 division operator,如果使用的 toolchain 已經有支援,就直接拿來使用
在 makefile 裡,對應的設定如下:
到這裡已經可以正常編譯,但屬於半殘,編譯出來的 Bin 載入到記憶體裡執行理論上是不會動的。所以在 follow-spec 階段,我們需要參考 ARM manual 及 ch8 porting guide 把原本的 dummy function 補上真正的程式碼
TBD...
經過前面兩個階段,試著將 Binary 載入到記憶體裡跑跑看,用來 debug 的工具不是 gdb 而是透過 JTAG,我習慣在編譯時同時使用 objdump 把 memory mapping dump 到檔案,debug 時,透過 JTAG 對「位址」設斷點,要對哪些位址設 BP 則是查看 dump 檔。同時準備筆和紙,debug 時,不像一般對應用程式的除錯,這個階段我們會很常需要紀錄一些位址還有 registers 的值,例如 IRQ 或 SVC mode 下的 SP 值是否為有效記憶體位址,若是無效位址,當 interrupt 發生時,也許連 ISR 都無法被正常執行。
由於使用 JTAG 可以讀取 registers 的值、對 memory 讀寫,在 debug 時,只要有耐心,都可以找到問題所在,找到問題後,再往回去找問題的發生原因。
節錄 dump 檔的部分內容
以下看幾個例子,稍微說明如何使用 JTAG 找到 bug
我們在 0x300090a4 的地方設立中斷點,發現 ucosii 執行到 0x300090a4 就無法繼續執行接下去的程式碼,很明顯在該位址附近的指令應該是造成了 exception,所以每次執行到就會回到 vector table 處重新執行
將 memory 0x300090a4 附近的指令 dump 出來,我們看到了有對 memory 存取的 ldr 及 str 指令,但是現在還不能確定原因是甚麼
對照程式碼,這邊一開始會修改全域變數 OSRunning 的值
最後,我們看一下 objdump,發現 OSRunning 的宣告是 byte,我卻把它當作一個 word 用 str 指令去寫資料,很明顯這邊就會出大問題了,事實上也的確是 root cause
ucosii 卡在 0x300019d8 和 0x300019f4 間,我在這兩個位址設立中斷點,正常來說應該只會跑過一次,不過從下面 debug 訊息,可以看到不只一次被執行到,我忘記這邊是甚麼原因造成的 ;)
產生 IRQ 中斷後,就葛屁啦,為甚麼知道是產生 IRQ 中斷呢,最簡單的方式是觀察暫存器 CPSR 的值
檢查一下在 IRQ mode 時的 SP(r13) 值,很誇張的錯誤,我忘了初始化 SP 在 IRQ mode 的值,補上相關的程式碼後,就沒問題了
我使用 timer4 當作是 OS 的 tick timer,下面這個錯誤是當 timer 觸發幾次後,就會開始印出一堆垃圾出來,這個 bug 比較難找,但是只要有耐心的單步追蹤,最後還是會發現錯誤點。
總之,因為原先 critical section 實作會造成 nested interrupt,但是 irq handler 並不支援巢狀中斷,在中斷還沒處理完又發生中斷,不斷的中斷下去,把分配給 irq 的 stack 吃光了,所以重新修改 critical section 的保護方式即可
將 產生的 Bin 燒錄到 DMA-2440 的 nand flash 上,開機後 bootloader 自動載入到記憶體執行,拍的很模糊,可以看到有3個 tasks(task0, task1, supertask) 不斷地在 context-switch
當 porting 一個 embedded os 時,除了 arch dependent 的部份外,還要補上 board(soc) support 的程式碼,例如 GPIO 初始化、記憶體初始化、那些拉裡拉雜有的沒的,這邊我用偷吃步的方式,因為 bootloader 會將 ucosii 載入到記憶體執行,所以我假設剛剛說的那些東西都在 bootloader 作好了,所以我就省略一些初使化的程式碼,讓事情簡單點。
Download 程式碼...
之前曾將 Prex 移植到 GTA02 上,由於 Prex 已經支援 ARM arch,所以當時的工作主要是補上對 device(board) GTA02 的支援,例如 uart driver, timer isr 等,對移植 OS 來說,對於 arch 的支援是指甚麼呢,OS 負責處理的工作有 task management、memory management 、schedule 等,以排程來說,系統同時間有多個 tasks 等著使用 cpu ,OS 選擇優先權最高的 task 執行,這個動作會需要 context-switch,由於不同 arch 有不同的 register 因此這個部份是屬於 arch dependent
另外還有 critical section 的保護,保護 critical section 最簡單的方法就是透過 Disable Interrupt 的方式,而 interrupt 的控制也是和 arch 相關,對 ARM arch 我們可以透過修改 register CPSR 的 I、F bit ,而 Ch8 講的也就是將上述的兩件事補齊。
在一頭鑽進移植的工作之前,先看一下 release note,ucosii 的 release note 寫的很好,很清楚告訴我們新增了哪些檔案,有哪些新的 define、struct,或是哪些函式名稱改變了,這個部份的確幫助我許多。
我把移植 ucosii 分成三個階段,分別是 compile 階段、follow spec 階段、debug 階段。
compile 階段要達到的目的很簡單,先寫個 makefile 讓下載回來的 ucosii 程式碼可以編譯,不會有錯誤訊息,compiler 跟你說少甚麼就補甚麼,少甚麼函式就先補個 dummy function,這邊需要的只是基本判讀錯誤訊息的能力
幾個 dummy function 的例子
一開始就告訴我們需要 app_cfg.h、os_cfg.h、os_cpu.h,用 touch 把這三個檔案生出來,檔案內容都是空的,重點只是先要可以編譯而已,見招拆招。
Recompile,發現這樣的錯誤,想都不用想,我們一定是少了 typedef,由於不同 cpu arch 的 word length 是不一樣的,例如,你不能保證每個 arch 上的 long 都是 4 bytes 吧,所以透過這樣的方式以達到 portable 的目的。
其中 OS_STK 是 stack 的單位,在作 context-switch 時我們需要將 registers 存入 stack 裡,由於 ARM 是 32-bit microprocessor,所以在 os_cpu.h 裡,我補上以下的 typedef:
前面說過,critical section 的保護是 arch dependent 的,所以在 ucosii 的程式碼裏面到處可以看見 OS_ENTER_CRITICAL() 及 OS_EXIT_CRITICAL(),但將這兩個函式定義交給我們實作,一樣先寫兩個 dummy function,記住我們的目的只是先讓編譯的階段可以順利達成,函式的真正實作則是放在 follow-spec 階段
這邊缺少的 function 有 OSDebugInit() OSInitHookBegin() OSInitHookEnd() OSTaskCreateHook() OSTaskDelHook() OSTaskIdleHook() OSTaskStatHook() OSTaskStkInit() OSTaskSwHook() OSTCBInitHook() OSTimeTickHook() OSCtxSw() OSIntCtxSw() OSStartHighRdy() OSTickISR()
至於是要定義在 .h .c 或 .s 檔裡,參照 ch8 porting guide,可以清楚知道這些 dummy function 分別要定義在哪些檔案裡
最後,需要注意的是下面的錯誤訊息,因為 ARM 並不支援除法指令(只有加、減、乘),所以要透過程式支援 modular operator 或 division operator,如果使用的 toolchain 已經有支援,就直接拿來使用
在 makefile 裡,對應的設定如下:
到這裡已經可以正常編譯,但屬於半殘,編譯出來的 Bin 載入到記憶體裡執行理論上是不會動的。所以在 follow-spec 階段,我們需要參考 ARM manual 及 ch8 porting guide 把原本的 dummy function 補上真正的程式碼
TBD...
經過前面兩個階段,試著將 Binary 載入到記憶體裡跑跑看,用來 debug 的工具不是 gdb 而是透過 JTAG,我習慣在編譯時同時使用 objdump 把 memory mapping dump 到檔案,debug 時,透過 JTAG 對「位址」設斷點,要對哪些位址設 BP 則是查看 dump 檔。同時準備筆和紙,debug 時,不像一般對應用程式的除錯,這個階段我們會很常需要紀錄一些位址還有 registers 的值,例如 IRQ 或 SVC mode 下的 SP 值是否為有效記憶體位址,若是無效位址,當 interrupt 發生時,也許連 ISR 都無法被正常執行。
由於使用 JTAG 可以讀取 registers 的值、對 memory 讀寫,在 debug 時,只要有耐心,都可以找到問題所在,找到問題後,再往回去找問題的發生原因。
節錄 dump 檔的部分內容
以下看幾個例子,稍微說明如何使用 JTAG 找到 bug
我們在 0x300090a4 的地方設立中斷點,發現 ucosii 執行到 0x300090a4 就無法繼續執行接下去的程式碼,很明顯在該位址附近的指令應該是造成了 exception,所以每次執行到就會回到 vector table 處重新執行
將 memory 0x300090a4 附近的指令 dump 出來,我們看到了有對 memory 存取的 ldr 及 str 指令,但是現在還不能確定原因是甚麼
對照程式碼,這邊一開始會修改全域變數 OSRunning 的值
最後,我們看一下 objdump,發現 OSRunning 的宣告是 byte,我卻把它當作一個 word 用 str 指令去寫資料,很明顯這邊就會出大問題了,事實上也的確是 root cause
ucosii 卡在 0x300019d8 和 0x300019f4 間,我在這兩個位址設立中斷點,正常來說應該只會跑過一次,不過從下面 debug 訊息,可以看到不只一次被執行到,我忘記這邊是甚麼原因造成的 ;)
產生 IRQ 中斷後,就葛屁啦,為甚麼知道是產生 IRQ 中斷呢,最簡單的方式是觀察暫存器 CPSR 的值
檢查一下在 IRQ mode 時的 SP(r13) 值,很誇張的錯誤,我忘了初始化 SP 在 IRQ mode 的值,補上相關的程式碼後,就沒問題了
我使用 timer4 當作是 OS 的 tick timer,下面這個錯誤是當 timer 觸發幾次後,就會開始印出一堆垃圾出來,這個 bug 比較難找,但是只要有耐心的單步追蹤,最後還是會發現錯誤點。
總之,因為原先 critical section 實作會造成 nested interrupt,但是 irq handler 並不支援巢狀中斷,在中斷還沒處理完又發生中斷,不斷的中斷下去,把分配給 irq 的 stack 吃光了,所以重新修改 critical section 的保護方式即可
將 產生的 Bin 燒錄到 DMA-2440 的 nand flash 上,開機後 bootloader 自動載入到記憶體執行,拍的很模糊,可以看到有3個 tasks(task0, task1, supertask) 不斷地在 context-switch
當 porting 一個 embedded os 時,除了 arch dependent 的部份外,還要補上 board(soc) support 的程式碼,例如 GPIO 初始化、記憶體初始化、那些拉裡拉雜有的沒的,這邊我用偷吃步的方式,因為 bootloader 會將 ucosii 載入到記憶體執行,所以我假設剛剛說的那些東西都在 bootloader 作好了,所以我就省略一些初使化的程式碼,讓事情簡單點。
Download 程式碼...
星期三, 6月 24, 2009
金面山
金面山,登山口在內湖環山路上,我知道的有三個登山口,我習慣從環山路一段136巷爬起。清朝時台北城的城牆石頭就是由此地開採,再透過鄰近的基隆河載運石塊,現在還留有採石場遺蹟。也因為如此,有些路段不像爬山,倒像是在攀岩,得拉著繩索,手腳並用和石塊奮鬥。
如果不是因為愛,我不會連三拉三,連續三個週末攀爬,踏著輕快的腳步,在山林裡行走,最後抵達三角點,在石頭上休息吹風,眺遠。我在這裡看到了可愛的五色鳥,還有剛被選為台灣國鳥的台灣藍鵲,看見松鼠穿越在樹林間,我真的很開心。
上個週末,變換路線,先到竹月寺,再轉往論劍亭,就是這條路線讓我鐵腿到昨天,大約三百到五百公尺長的距離,整面山璧角度超過50度,加上我又好傻好天真的揹了一本很厚的 device driver 想說攻頂時可以拿出來當枕頭睡(誤...)
總之,我最後累攤了,書也沒拿出來過,也沒爬到剪刀石,回來還被 olv 笑,所以這週我要再帶著 olv 一起去...科科 ;)
如果不是因為愛,我不會連三拉三,連續三個週末攀爬,踏著輕快的腳步,在山林裡行走,最後抵達三角點,在石頭上休息吹風,眺遠。我在這裡看到了可愛的五色鳥,還有剛被選為台灣國鳥的台灣藍鵲,看見松鼠穿越在樹林間,我真的很開心。
上個週末,變換路線,先到竹月寺,再轉往論劍亭,就是這條路線讓我鐵腿到昨天,大約三百到五百公尺長的距離,整面山璧角度超過50度,加上我又好傻好天真的揹了一本很厚的 device driver 想說攻頂時可以拿出來當枕頭睡(誤...)
總之,我最後累攤了,書也沒拿出來過,也沒爬到剪刀石,回來還被 olv 笑,所以這週我要再帶著 olv 一起去...科科 ;)
星期四, 6月 18, 2009
樹
星期日, 5月 17, 2009
訂閱:
文章 (Atom)