星期五, 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!」

星期三, 5月 13, 2009

DirectFB on Beagleboard

DirectFB 是 graphical library,支援 input event handling、window management 等,我們藉由 DirectFB 可以在 embedded system 上建立 GUI 的環境,DirectFB 透過 framebuffer 或 /dev/mem 控制底層硬體,所以在開始之前,先確定這兩條路在 kernel 裡有一條是通的,若是走 fbdev 別忘了在 rootfs 裡建立 /dev/fb0。



雖然是「DirectFB on Beagleboard」,但和 beagleboard 沒有太大關係,我只是把它當作 demo 的平台。CPU 是 TI OMAP3530 (Cortex-A8 / armv7a) 我並沒有特別針對 armv7a 作最佳化,同時在編譯 DirectFB 時也沒有將 beagleboard 支援的 3D 功能 enable (少了 SDK...),所以以下的動作是可以套用在其他 arm 的平台上。

單純想要手動去建立一個系統,從 BusyBox 開始編起,慢慢拼湊自己想要的系統,唯一的好處是整個過程會遇到很多問題,所以會學到一些東西,對系統的掌握也更多。OpenEmbedded 是個好東西,只是每次下個指令就把系統建好的感覺很不踏實 ;)



下載每個套件的 source,由於套件的相依性,因此由 zlib 開始編譯最後則是 Lite,Lite 是以 directFB 為基礎的 toolkit,編譯它的目的只是為了執行它的 samples 驗證 directFB 是可以動的(此外,Lite 也是 DFBterm 的相依套件),如果有 touchscreen 那麼 tslib 是必要的套件。

可以直接下載每個套件對應的 build-script,直接修改,例如:
make clean
STAGING=/home/sean/openmoko/embedded-gui/dist
./configure --prefix=/usr \
--host=arm-none-linux-gnueabi \
--enable-shared=yes --enable-static=yes \
CFLAGS="-I${STAGING}/usr/include" \
LDFLAGS="-L${STAGING}/usr/lib"
LIBS="-lz"

make DESTDIR=${STAGING} install
把 STAGING 改成你自己的工作目錄, --host 則是你使用的 cross-toolchain。另外, jpeg 及 directfb 先天營養不良,從官網抓下來的套件就無法順利編譯或安裝,所以下面的 patch 要先打上...

fix_errro_when_install.patch
fix_missing_libtool_error.patch
add_missing_header_file.patch

在編譯 (cross-compile) 套件時,configure 的動作要特別小心,好一點的狀況是有 error 產生,最麻煩的是 configure 時告訴你沒有問題,編譯時卻發生錯誤,事實上在 configure 程序就已經出錯了,通常是在作環境變數的檢查時 configure 搞混了,所以我會利用 screen 將整個過程紀錄下來,再稍微看一下。

以下面例子而言,在 configure 前,特別指定 LIBPNG_CONFIG 的用意是因為 configure 會找到 /usr/lib/libpng-config,但這是我 host (x86) 上的,並不是真正要的
STAGING=/home/sean/openmoko/embedded-gui/dist

LIBPNG_CONFIG=${STAGING}/usr/bin/libpng-config ./configure \
--prefix=/usr \
--host=arm-none-linux-gnueabi \
--target=arm-none-linux-gnueabi \
--enable-static=yes --enable-shared=yes \
...
編到 directFB 套件我們就可以先把所有產生的 header / lib / binary 等,放到 rootfs 上作測試,執行 dfbscreen 如果沒有意外的話會給你沒營養的錯誤訊息:
   ~~~~~~~~~~~~~~~~~~~~~~~~~~| DirectFB 1.3.1 |~~~~~~~~~~~~~~~~~~~~~~~~~~
(c) 2001-2008 The world wide DirectFB Open Source Community
(c) 2000-2004 Convergence (integrated media) GmbH
----------------------------------------------------------------

(*) DirectFB/Core: Single Application Core. (2009-05-15 09:48)
(!) DirectFB/core/system: No system found!
(!) Tools/Screen: DirectFBCreate() failed!
--> No (suitable) implementation found!
strace 試著找出問題點,是因為編譯 directFB 時把 /home/sean/openmoko/embedded-gui/dist 路徑寫進產生的 library 及執行檔裡,所以執行 dfbscreen 時,如果在該目錄裡找不到它需要的,便丟出錯誤訊息。找不到是必然的,因為編譯出的檔案最後是放在 rootfs 的 / 目錄下。

路徑寫到編譯產生的檔案裡是 linker 參數 rpath 造成的,如果我們是在系統下編譯套件並把該套件安裝在系統下,那麼寫入路徑是沒有問題的,但 cross-compile 就會有麻煩了,假設你編譯了套件 A 並將它安裝在 ${STAGING} ,假若套件 B 相依於套件 A,在編譯套件 B 時必須指定套件 A 的安裝路徑,這時候就有可能發生 rpath 的問題了,我是透過修改 configure 檔,把參數 rpath 改成 rpath-link 解決這個問題,編譯後可以檢查是否還有 rpath 的影響:
#!/bin/bash
find $1 -name "*" | xargs arm-none-linux-gnueabi-readelf -d | grep RPATH
change_rpath_to_rpath-link.patch
jpeg_rpath_to_rpath-link.patch

討論 cross-compile 的路徑問題可以參考 Avoiding libtool minefields, 詳細說明會遇到的狀況。繼續編譯 Lite 會出現錯誤,類似:
arm-none-linux-gnueabi-ranlib .libs/liblite.a
creating liblite.la
/bin/sed: can't read /usr/lib/libfusion.la: No such file or directory
libtool: link: `/usr/lib/libfusion.la' is not a valid libtool archive
make[1]: *** [liblite.la] Error 1
找不到 /usr/lib/libfusion.la,root cause 也是因為路徑的問題,函式庫之間會有相依性,我們也許只知道某個套件需要函式庫 A,但不清楚 A 是相依於哪些函式庫,libtool / .la 則是可以用來解決這樣的問題,只是在 cross-compile 時,反而造成問題。以下節錄 libdirectfb.la 檔:
...
# The name of the static archive.
old_library='libdirectfb.a'

# Libraries that this one depends upon.
dependency_libs=' -L/home/sean/openmoko/embedded-gui/dist/usr/lib \
/usr/lib/libfusion.la /usr/lib/libdirect.la -lpthread \
/home/sean/openmoko/embedded-gui/dist/usr/lib/libjpeg.la \
/usr/lib/libpng.la -lz -lm /usr/lib/libfreetype.la \
/usr/lib/libts.la -ldl
...
dependency_libs 會提供該套件相依的 library,但是路徑卻是錯的,解決的方法是把所有 *.la 的 dependency_libs 注解掉,取而代之的是在 configure 時就指定 linker or compiler 所需的參數:
#!/bin/bash
find $1 -name "*.la" | xargs sed -i 's/dependency_libs/#dependency_libs/g'
最後附上 lite_simple 在 beagleboard 上的執行畫面

星期一, 5月 11, 2009



星期日一早帶齊裝備後就到內湖山裡做野採,對象是青苔,除了長在山壁上的,生長在石頭上的青苔也是這次採集的目標,溪邊的山璧很適合青苔的潮溼、陰暗生長環境。



在山裡(或溪裡)活動,保持靈敏聽覺和嗅覺是很重要的,如果聽到奇怪的聲音或聞到奇怪的味道,慢慢地退到安全的地方。往溪水下游的方向走去,走沒幾公尺先是聞到一股惡臭,同時聽到一群拍打翅膀的嗡嗡聲,經驗法則附近有屍體,就回頭往上游方向了...

想起小時候和表弟在鄉下大水溝裡抓魚的恐怖記憶,抓的很開心的時候,旁邊浮來全身發漲發黑的死豬(還有死雞),所以我到現在還是會害怕看到水裡的麻布袋 ;)

人生就像飄在水面的麻布袋,不打開看,你永遠不知道裏面裝甚麼死人骨頭...









遇到剛羽化的蜻蜓幼蟲水蠆(ㄔㄞ')






儘量不要一個人跑到山裡,很難預測會有甚麼突如其來的事情發生,找個伴。這次的主角青苔正在育嬰室,如果有活下去就可以出來亮像了 ;)

比肥的



星期三, 5月 06, 2009

Bootable USB Image

前幾天,不務正業的幫公司處理工廠生產的問題,作為代工廠,系統影像檔是由客戶提供,所以測試程式不可能讓你包在出貨用的 Image 裡,一來是因為「髒」,再者是程式自身的需求或許需要某些套件的搭配,比較好的方式為測試程式量身打造一個系統。

要求很簡單,Boot From USB、越小越好、開機後直接執行測試程式,且可以簡單、快速的大量複製該測試系統,Moblin Image Creator 可以幫助我們簡化整個過程,把整個框架建好,我們可以專心在整合測試程式,同時安裝程式需要的套件、modules,接著手動修改設定檔,整個過程就像在拼圖一樣。即便有了 MIC,手動的地方還是不少,最後作出來的影像檔大小 300 MB,雖然還可以縮減,但以現在隨身碟的容量及 USB 2.0 的傳輸速度,其實意義不大;對於大量複製的要求,工廠只要執行 dd bs=1024 if=usb.img of=/dev/sd? 便可以做好測試用的隨身碟。

學習應該是這樣,首先你找到黑盒子幫你解決問題,接下來要去了解黑盒子,最後你試著做出一個很陽春但可以用的透明盒子。我將整個過程抽出重新寫成 Scripts,一樣可以作出符合要求的檔案 ;)

重點是,這樣的過程,你必須不斷地把做好的 Image 寫到隨身碟,關機,重新開機(Boot From USB),檢查作出來的隨身碟能不能正常開機,如果你真的不斷重複這樣的過程,我只能說連猩猩都會利用工具釣魚了... ;)



透過 QEMU,不必重新開機,就可以測試我們做好的隨身碟,利用 lsusb 得到 usb flash drive 的 vendor 及 product id 後,利用 qemu 模擬整個開機的過程

sudo qemu usb.img -no-acpi -usbdevice host:3538:0050





不務正業,我就是討厭 Notebook...

Kenting

四月的某個週末,因為姊夫參加在墾丁舉辦的國際鐵人三項比賽,就趁著這個機會和家人一起再回到墾丁,還好,今年四月的氣溫還是舒服的 ;)

我們不是參賽者,比較像是自由行的人,就這樣開著車沒有目地的到處跑。跑去海角七號的場景拍照,跑去四重溪享受只有我們一家人的溫泉,天空還飄著毛雨,跑去只有我們的沙灘,順便找所謂的港口茶,最後在慢速的開在漂亮的佳鵝公路上。





或許是被海趨使,回到台南後,就立刻拖著我家的狗跑到黃金海岸,站在海裡,迎著海浪的沖擊,對著海大笑(狗爬式很搞笑),等到太陽西下,遠方燈塔的橘燈和藍燈亮起,瞬間陷入沈寂裡。

像這樣把時間留給家人,也是不錯的生活(茶)...