星期五, 12月 11, 2009

Probationary period

不知不覺中就度過三個月的試用期了,邁向第六個月,雖然剛進公司的第一個星期我就想離職了 ,補上從公司看 101 的夕陽照。



從一開始遠在美國的印度主管和同事們,部門在台灣只有我一個工程師,到現在陸陸續續已經有四個同事加入,繼續觀察下去囉,呵。

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

星期三, 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 裡都會被使用到
#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"
"mrs %0, cpsr\n\t"
"orr r8, %0, #0xC0\n\t"
"msr cpsr_c, r8\n\t"
output operand list
: "=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

最後一個上班日

第一份工作在今天結束,將近五年(2004.08 - 2009.06)的歲月裡,感謝在我身邊來來去去的同事和長官們 ;)

公司頂樓最後一拍,這裡時常可見飛機起降於松山機場

星期五, 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 程式碼...

星期三, 6月 24, 2009

金面山

金面山,登山口在內湖環山路上,我知道的有三個登山口,我習慣從環山路一段136巷爬起。清朝時台北城的城牆石頭就是由此地開採,再透過鄰近的基隆河載運石塊,現在還留有採石場遺蹟。也因為如此,有些路段不像爬山,倒像是在攀岩,得拉著繩索,手腳並用和石塊奮鬥。





如果不是因為愛,我不會連三拉三,連續三個週末攀爬,踏著輕快的腳步,在山林裡行走,最後抵達三角點,在石頭上休息吹風,眺遠。我在這裡看到了可愛的五色鳥,還有剛被選為台灣國鳥的台灣藍鵲,看見松鼠穿越在樹林間,我真的很開心。





上個週末,變換路線,先到竹月寺,再轉往論劍亭,就是這條路線讓我鐵腿到昨天,大約三百到五百公尺長的距離,整面山璧角度超過50度,加上我又好傻好天真的揹了一本很厚的 device driver 想說攻頂時可以拿出來當枕頭睡(誤...)



總之,我最後累攤了,書也沒拿出來過,也沒爬到剪刀石,回來還被 olv 笑,所以這週我要再帶著 olv 一起去...科科 ;)

星期四, 6月 18, 2009

內湖這個地方除了科學園區外,有山還有湖,這個環境可以讓我在工作和生活間暫時找到一個平衡點。



曾經聽人說過,如果早幾秒或晚幾秒鐘,悲劇就不會發生,這樣的事情就這麼巧發生在我面前,應該是上星期的連日大雨,造成土石的滑動,星期日的中午騎車行經這條通往三軍總醫院的捷徑上,就像電影一樣,旁邊山壁上的一棵樹就在我面前倒下來,就僅僅相差約莫一個機車身的距離,我想如果樹晚個兩秒倒下,也許我就會像那輛汽車一樣了(車頂凹陷+擋風玻璃碎裂)。

另外讓我驚訝的是中華民國的警察竟然也會有如此的效率(原來不是只會躲起來泡茶...),跑回家拿相機再回來,條杯杯也剛好來處理了,真不錯... ;)

白額高腳蛛

某天晚上下班回家,伸手準備開啟房門,發現這個傢伙就停在門把上,俗稱拉牙,雖然是好人一枚,但是為了避免嚇到他人被其他不知情房客誤殺,最後還是把它帶到外面放了。





真的蠻大的,大蜘蛛這個名字不是叫假的,目測兩腿拉直應該會有 15 ~ 20 公分,蜘蛛本應是八條腿,它卻只有六條腿,看來是個少了一對腿的半殘蜘蛛人...

星期日, 5月 17, 2009

Marley & Me

「一條沒有規矩的狗和一對新婚夫妻的生活,最後男主角死了,兩個配角也生了三個小孩,The End!」