顯示具有 embedded system 標籤的文章。 顯示所有文章
顯示具有 embedded system 標籤的文章。 顯示所有文章

2013年1月14日 星期一

uCLinux--如果沒有...

最近剛剛拜讀完人家,一些在linux底下的loader的機制,也就是牽涉到如何載入share lib跟OS如何分配管理elf程式的部分,回想uCLinux到底有何不同,想不到真的大大不同!!我把uClinux想簡單了

底下是另外一篇解釋uCLinux跟一般linux不一樣的地方,過去總是以為簡單的沒有MMC跟浮點數(floating point)
http://www.linuxjournal.com/article/7221

因為沒有MMU,就不支援Virtual Memory(VM),在這一節上,想不到會有許多差異

直覺,沒有VM,那麼記憶體應該是直接攤在記憶體中,且應該是連續的
因為沒有MMU,過去2^n配置記憶體,考慮到環境,也不可行,必須改用其他演算法,免得有記憶體破碎的問題
Heap要自己管理,也就是可能直接深入kernel,由kernel控制
沒有fork(),讓我實在意外,uCLinux只有提供vfork,使用 vfork() 會使得 parent process suspend 直到child process結束或執行exec()為止。@@a multi-process認知都有點不一樣了,我看muti-thread就更不用想了
只支援 flat executable format (bFLT), 這有兩種型態:
一、code text & data 都是 relocatable
二、使用 PIC 碼 (Position Independent Code)只有部份 data 需要 relocation 即可。
其中第二項衍生出 XIP (eXecute In Place) ,就是程式可以直接在 ROM上面執行的方式,因為 ROM 是 read only,可以被多個 instance share 使用。在這裡似乎uCLinux佔到了一點便宜,因為位址是固定的,外加用事read-only,那麼從新定位code text變成沒有必要的事情,也就是不用plt.got這個表了。可是事情也沒那麼樂觀,因為不是所有的硬體平台都支援PIC orz

回想想用gcc -shared 選項表示使用loading time relocate,但無法幫你在 bFLT格式中製作shared library。 這裡只提一個重要概念,shared library 必須是 XIP ,否則在每個uClinux application 都會產生一份 copy --- 這種情形比 static linking還要糟糕!

也就是說,在uCLinux底下開發程式要注意的點比一般的linux程式還要多的限制,不是簡單換個distribution那樣而已,也不是簡單的抽換到glibc這個lib

2012年4月18日 星期三

Cloud Projector

最近都在弄硬體的東西,反倒是忽略了這個blog,先放一兩張之前用BeagleBoard做的projector,理想上就是利用BB加連上投影機,然後用瀏覽器,比如說平板上面的瀏覽器來作遠端遙控,至於投影片是放在網際網路上面的
螢幕試用台代替投影機,可以看到BB只有外加上一個USB無線網卡,本來電源是想要用電池的,可惜市面上買到的電池組裝起來電流不夠穩定,所以電源還是接到變壓器,改天有空自己再來作一個。可以看到平板上面會顯示跟投影機上面一樣的縮圖

可以看到上面細項的參數,主要就是一個URL跟一個頁數還有目前頁數的顯示以及一些簡單的跳頁、上一頁、下一頁

目前可以轉換網頁跟pdf檔案,以後應該開始考慮轉換google的投影片,一樣有空在研究吧

2012年3月22日 星期四

LCD之framebuffer(4)

終於在網路上看到為何framebuffer會比實際上來的大,以前有人會解釋說是為了作double-buffer,但是有時候size又不是單純的一倍大小,這樣很難自圓其說,後來發現有另外一個原因,那就是為了smooth moving,如果有打過一些以前DOS小遊戲的人(有不小心透露出自己年紀不小嗎XD),遊戲主角移動單位是一格一格的,但是移動的時候卻是平滑移動的動畫,不是跳格的方式,這時候多出來的framebuffer空間就可以作為平滑移動,只要改變指標的位置,就不用會產生跳格的感覺

另外經由Linux驅動程式一書的解釋,framebuffer屬於user space的driver,所以效能會比kernel space來的差,所以表示,如果說要使用圖形顯示,但是又想繞過xwin,或許framebuffer是個不錯的選擇,但是想要在比desktop還要差的硬體下壓榨出更多的效能,可能就得自己對driver開刀了,這恐怕是個大工程,當然很多人會想要使用DSP硬體支援,這也是時下主流平板的選擇

2012年3月21日 星期三

Linux驅動程式--chapter 2

這一章節簡單的給了個module的入門,一個只是用來insmod跟rmmod的moduule

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int __init hello_init(void){
  printk(KERN_ALERT "Hello, world\n");
  return 0;
}
static void __exit hello exit(void){
  printk("KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
與一般user space不同,由於module運行於kernel space,所以並不連結一般的lib,所以類似printf就不能使用,只能使用printk,KERN_ALERT是一個macro,後面沒有逗點,module_init點出insmod module就運行的function,相對的module_exit則是rmmod的時候

設計module必須考量到

  • 是kernel space or user space(有些驅動程式是可以為user space,但是有好有壞)
  • module變數的race condition
  • module必須是reentrant
  • module的lifetime幾乎等同kernel,從insmod到rmmod(往往就是開機到關機),中間變數一直存在,並不隨著被服務的process結束而結束
  • module的記憶體有限,堆疊不可能配置太大的空間
  • module往往跟目前服務的process有很大的關係,可以使用struct task_struct中的current指向目前的process
  • module的相依性處理不完全在於程式,在於管理者必須知道使用modprobe來追蹤,但是這也表示module往往跟版本有很大的關係


在headers內定義了許多macro是供給modinfo用的

  • MODULE_LICENSE : 是使用GPL or BSD還是其他
  • MODULE_AUTHOR : 作者資訊
  • MODULE_VERSION : 版本,通常表示支援的kernel version等等
  • MODULE_DESCRIPTION : 描述
  • MODULE_ALIAS : alias name
  • MODULE_DEVICE_TABLE : 支援的device


有些關鍵字是C語言內沒有的,例如__init跟__exit,這是給compiler用的,分別表明該函數是初始化以及結束時該呼叫的,另外還有__initdata與__exitdata表示初始配置資料的函數跟離開時後歸還空間的函數,往往用於hotplug

其他關於編譯的細節以及一些版本號碼控管有空再說,本身這是一章節談論到很多關於kernel module的觀念

這本書每章節後面都會簡單的summary這章節的內容,蠻有幫助的


2012年3月18日 星期日

OpenWrt這東西

之前就有在網路上論壇看到人家討論,還沒仔細看過,最近在網路上找問題的時候看到
https://openwrt.org/
似乎是一個為了wireless router作為設計基準的distribution,特色應該就是遷入系統,對於封包的管理,防火牆的設計等等作特殊設計的套件,不知道有沒有設計好的管理介面?有空的時候再來弄個硬體來體驗看看

2012年3月17日 星期六

編譯open ssl與wpa_supplicant(補)

本以為高高興興的編譯過之後,接下來就是完成無線網卡的module就可以快快樂樂得上網了,結果才知道自己天真了orz

首先是怎樣都無法wpa_supplicant成功,仔細看了許久的設定檔案,應該沒有錯誤(改過幾種),或者版本有問題(另外試驗0.61),再來懷疑是openssl沒有編譯好,找了幾個編譯版本,還修改了些參數(目前還是沒有編譯出.so,但是有編譯出.a),跟著甚至把ssl的lib用static link到wpa_supplicant裡面;又或者懷疑busybox是不是有問題,哪些tool沒裝?

最後才發現,原來要改kernel阿~~~囧~必須要打開CONFIG_PACKET選項阿~~~

好啦,打開之後,發現wpa_supplicant可以過了,想不到事情還沒結束,先看看需要dhcp,那表示我要編譯dhcpclient囉?嗯嗯~busybox有簡易的版本udhcpc,那就使用吧,用了之後竟然完全好似沒有作用!?去開AP的設定來看,有連上來阿~也分配了位置,又是上網爬文,發現原來udhcpc並不會自動更改設定,要透過script,在busybox解開的目錄內$(busybox)/examples/udhcp/simple.script,拷貝到機器上變成/usr/share/udhcpc/default.script,這樣一來只要使用updhcpc -i wlan0,ifconfig就可以看到系統自動幫我們設定好ip、netmask、nameserver...,應該可以上網了吧,ping又失敗了..............真的無力到了極點,我又開始"疑神疑鬼"了,最後答案是.....

原來的route路徑跟wlan衝突阿.....eth0跟wlan0兩者都是192.168.1.x的網域,所以系統大概先註冊先贏,率先去使用eth0的路徑吧orz,最後先把eth0關閉,終於可以上網了,真的是遠兜轉了

這只能說,desktop distribution還真的方便許多,嵌入式系統還真多東西自己要take care

2012年3月15日 星期四

編譯open ssl與wpa_supplicant

wpa_supplicant用以支援WPA等等的加密演算法的無線網路連線的工具,既然要提到加密,難免需要ssl支援,所以外加必須編譯open ssl,而且open ssl必須先使用wpa_supplicant裡面的patch檔案patch過,這裡我所使用的是wpa_supplicant 0.7.3與openssl 0.9.8i
先編譯open ssl

  • patch -p0<wpa_supplicant-0.7.3/patches/openssl-0.9.8i-tls-extensions.patch
  • ./Configure linux-elf-arm -DB_ENDIAN linux:'arm-linux-gcc' shared --prefix=$ROOTFS/openssl
  • make && make install

接著編譯wpa_supplicant

  • 找到Makefile將CC修改為arm-linux-gcc(依照你的toolchain)
  • cp defconfig .conf
  • 修改.conf中的參數
    • CC=arm-linux-gcc -L $(ROOTFS)/openssl/lib/
    • CFLAGS += -I$(ROOTFS)/openssl/include/
    • LIBS += -L$(ROOTFS)/openssl/lib/
  • make
另外中間發現,實在micro2440的光碟片有點太糟糕,竟然把不同cpu的toolchain放在一起,搞得我還拷貝錯lib跟ldconfig,試驗了老半天,怎麼都是Illegal instruction,因為根本無法載入library阿~天啊!!

2012年3月14日 星期三

micro2440編譯核心

只要使用廠商提供的核心設定檔案下去更改就簡單得多了,主要應該是卡在一個機器型號的設定上面,使得在super vivi還是uboot上面送出的參數會產生一些不匹配的問題,指令類似這樣
copy config_xxxx .config

不過只細看,設定檔案刪除了很多東西,比方一些檔案型態的支援,如果要支援fat跟ntfs記得要把他們編譯進去,另外就是編碼的選擇,記得在native language上選取要支援的編碼,免得有亂碼或者utf-8不支援的問題

可是我好像忘記把模組安裝上去XD另外順便在這裡筆記一下好了,下次要準備編譯一些wireless tools跟wpa_supplicant套件,那表示順便會編一到open ssl,這樣可能就順便編譯一下ssh好了,實在不大喜歡使用serial port,把網路弄起來用ssh連線會比較好一點

2012年3月13日 星期二

[轉載]YAFFS檔案系統

來自http://jnds.yo2.cn/articles/%E5%9C%A8nand-flash%E4%B8%8A%E5%BB%BA%E7%AB%8Byaffs2%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%80%EF%BC%89.html

經過了半個多月的努力,終於搞定nandflash的mtd驅動和上層的yaffs2文件系統。這半個多月來幾乎每天都要和挫敗感鬥爭,每天都要忍 受這個方面,那個方面的bug。想想自己這半個多月來,也算看不少資料,得到不少人的幫助,總算是有點心得。鑑於國內搞yaffs2文件系統方面的資料還 是很少,就把自己的心得拿出來與大家共享。
      不說閒話了,先介紹一些背景資料    一. 閃存
我們常說的閃存其實只是一個籠統的稱呼,準確地說它是非易失隨機訪問存儲器(NVRAM)的俗稱,特點是斷電後數據不消失,因此可以作為外部存儲器使用。 而所謂的內存是揮發性存儲器,分為DRAM和SRAM兩大類,其中常說的內存主要指DRAM,也就是我們熟悉的DDR、DDR2、SDR、EDO等等。閃 存也有不同類型,其中主要分為NOR型和NAND型兩大類。
閃存的分類
NOR型與NAND型閃存的區別很大,打個比方說,NOR型閃存更像內存,有獨立的地址線和數據線,但價格比較貴,容量比較小;而NAND型更像硬 盤,地址線和數據線是共用的I/O線,類似硬盤的所有信息都通過一條硬盤線傳送一般,而且NAND型與NOR型閃存相比,成本要低一些,而容量大得多。因 此,NOR型閃存比較適合頻繁隨機讀寫的場合,通常用於存儲程序代碼並直接在閃存內運行,手機就是使用NOR型閃存的大戶,所以手機的「內存」容量通常不 大;NAND型閃存主要用來存儲資料,我們常用的閃存產品,如閃存盤、數碼存儲卡都是用NAND型閃存。
這裡我們還需要端正一個概念,那就是閃存的速度其實很有限,它本身操作速度、頻率就比內存低得多,而且NAND型閃存類似硬盤的操作方式效率也比內存 的直接訪問方式慢得多。因此,不要以為閃存盤的性能瓶頸是在接口,甚至想當然地認為閃存盤採用USB2.0接口之後會獲得巨大的性能提升。
前面提到NAND型閃存的操作方式效率低,這和它的架構設計和接口設計有關,它操作起來確實挺像硬盤(其實NAND型閃存在設計之初確實考慮了與硬盤 的兼容性),它的性能特點也很像硬盤:小數據塊操作速度很慢,而大數據塊速度就很快,這種差異遠比其他存儲介質大的多。這種性能特點非常值得我們留意。
NAND型閃存的技術特點
內存和NOR型閃存的基本存儲單元是bit,用戶可以隨機訪問任何一個bit的信息。而NAND型閃存的基本存儲單元是頁(Page)(可以看 到,NAND型閃存的頁就類似硬盤的扇區,硬盤的一個扇區也為512字節)。每一頁的有效容量是512字節的倍數。所謂的有效容量是指用於數據存儲的部 分,實際上還要加上16字節的校驗信息,因此我們可以在閃存廠商的技術資料當中看到「(512+16)Byte」的表示方式。目前2Gb以下容量的 NAND型閃存絕大多數是(512+16)字節的頁面容量,2Gb以上容量的NAND型閃存則將頁容量擴大到(2048+64)字節。
NAND型閃存以塊為單位進行擦除操作。閃存的寫入操作必須在空白區域進行,如果目標區域已經有數據,必須先擦除後寫入,因此擦除操作是閃存的基本操 作。一般每個塊包含32個512字節的頁,容量16KB;而大容量閃存採用2KB頁時,則每個塊包含64個頁,容量128KB。
每顆NAND型閃存的I/O接口一般是8條,每條數據線每次傳輸(512+16)bit信息,8條就是(512+16)×8bit,也就是前面說的 512字節。但較大容量的NAND型閃存也越來越多地採用16條I/O線的設計,如三星編號K9K1G16U0A的芯片就是64M×16bit的NAND 型閃存,容量1Gb,基本數據單位是(256+ 8) ×16bit,還是512字節。
尋址時,NAND型閃存通過8條I/O接口數據線傳輸地址信息包,每包傳送8位地址信息。由於閃存芯片容量比較大,一組8位地址只夠尋址256個頁, 顯然是不夠的,因此通常一次地址傳送需要分若干組,佔用若干個時鐘週期。NAND的地址信息包括列地址(頁面中的起始操作地址)、塊地址和相應的頁面地 址,傳送時分別分組,至少需要三次,佔用三個週期。隨著容量的增大,地址信息會更多,需要佔用更多的時鐘週期傳輸,因此NAND型閃存的一個重要特點就是 容量越大,尋址時間越長。而且,由於傳送地址週期比其他存儲介質長,因此NAND型閃存比其他存儲介質更不適合大量的小容量讀寫請求。
二.MTD
MTD是memory technology Device的縮寫。MTD支持類似於內存的存儲器,它是底層硬件和上層軟件之間的橋樑。對底層來說,它無論對nor型或是nandflash都有很好的 驅動支持,對上層來說,它抽象出文件系統所需要的接口函數。同時由於flash自身的特別之處(既有類似塊設備的特點,又有類似字符設備的特點),MTD 可以把flash同時為塊設備和字符設備。有了MTD,編寫flash的驅動變得十分輕鬆,因為上層的架構都已經做好,我們只用看看flash的 datasheet,寫最底層的控制時序即可。
以下內容為翻譯自mtd官方網站http://www.linux-mtd.infradead.org/archive/index.html
mtd致力於為存儲器,尤其是flash,設計一個通用的linux下的子系統。
設計這個系統的目標在於,通過這個系統所提供的硬件驅動和上層系統之間的接口,我們可以方便的為新的硬件編寫驅動。
對於底層的硬件驅動來說,它們所以提供是讀,寫,擦除的流程。而文件的存儲形式是和他們無關的(如FTL,FFS2等等),用恰當的形式存儲用戶的數據那時上層系統關注的事情。
MTD的用戶模塊
MTD為用戶提供五種可以直接在用戶空間使用的模塊
字符設備
塊設備
flash轉換層
nandflash轉換層
JFFS2文件系統
三.yaffs2文件系統
針對於flash的文件系統有很多,據我瞭解有jffs(1,2,3),yaffs(1,2)。還有商業的三星開發的RFS(健壯文件系統),專門針對三 星自己的nand和onenand,從底層驅動到上層文件系統一條龍服務,而且號稱和fat格式100%兼容。當時看得我直流口水,心裡把三星恨的咬牙切 齒。 下面主要介紹一下開源的yaffs文件系統。
Yaffs(Yet Another Flash File System)文件系統是專門針對NAND閃存設計的嵌入式文件系統,目前有YAFFS和YAFFS2兩個版本,一般說來,YAFFS對 512byte/page以下都有很好的支持,而更大的頁就需要YAFFS2了,如2K/page。
Yaffs文件系統有些類似於JFFS/JFFS2文件系統,與之不同的是JFFS1/2文件系統最初是針對NOR FLASH的應用場合設計的,而NOR FLASH和NAND FLASH本質上有較大的區別,所以儘管JFFS1/2 文件系統也能應用於NAND FLASH,但由於它在內存佔用和啟動時間方面針對NOR的特性做了一些取捨,所以對NAND來說通常並不是最優的方案。
Yaffs對文件系統上的所有內容(比如正常文件,目錄,鏈接,設備文件等等)都統一當作文件來處理,每個文件都有一個頁面專門存放文件頭,文件頭保存了 文件的模式、所有者id、組id、長度、文件名、Parent Object ID等信息。因為需要在一頁內放下這些內容,所以對文件名的長度,符號鏈接對象的路徑名等長度都有限制。
前面說到對於NAND FLASH上的每一頁數據,都有額外的空間用來存儲附加信息,通常NAND驅動只使用了這些空間的一部分,YAFFS正是利用了這部分空間中剩餘的部分來 存儲文件系統相關的內容。同時由於支持的page變大,YAFFS2使用更多的spare space來存儲這些信息。在結構上YAFFS和YAFFS2有一定的不同,具體結構可以去看一看這篇文檔http://www.aleph1.co.uk/node/38
那麼這個文件系統是如何運作起來呢。
操作文件系統的第一步自然是取得SuperBlock了,Yaffs文件系統本身在NAND Flash上並不存在所謂的SuperBlock塊,完全是在文件系統mount的過程中由read_super函數填充的,不過有意思的一點是,由於物 理上沒有存儲superblock塊,所以NAND Flash上的yaffs文件系統本身沒有存儲filesystem的魔數(MagicNum),在內存中superblock裡的s_magic參數也 是直接賦值的,所以存儲在NAND FLASH上的任何文件系統都能被當作yaffs文件系統mount上來,只是數據都會被當作錯誤數據放在lost+found目錄中,不知道這算不算 yaffs文件系統的一個bug。
通常一個具體的文件系統在VFS的Super_block結構中除了通用的數據外,還有自己專用的數據,Yaffs文件系統的專用數據是一個yaffs_DeviceStruct結構,主要用來存儲一些相關軟硬件配置信息,相關函數指針和統計信息等。
在mount過程執行read_super的過程中,Yaffs文件系統還需要將文件系統的目錄結構在內存中建立起來。由於沒有super塊,所以需要掃 瞄Yaffs分區,根據從OOB中讀取出的yaffs_tags信息判斷出是文件頭page還是數據page。再根據文件頭page中的內容以及數據 page中的ObjectID/ChunkID/serial Number等信息在內存中為每個文件(Object)建立一個對應的yaffs_object對象。
在yaffs_object結構中,主要包含了:
    如修改時間,用戶ID,組ID等文件屬性;
    用作yaffs文件系統維護用的各種標記位如髒(dirty)標記,刪除標記等等;
    用作組織結構的,如指向父目錄的Parent指針,指向同級目錄中其他對象鏈表的     siblings雙向鏈表頭結構
此外根據Object類型的不同(目錄,文件,鏈接),對應於某一具體類型的Object,在Yaffs_object中還有其各自專有的數據內容
       普通文件:文件尺寸,用於快速查找文件數據塊的yaffs_Tnode 樹的指針等
       目錄:目錄項內容雙向鏈表頭(children)
       鏈接:softlink的alias,hardlink對應的ObjectID
除了對應於存儲在NAND FLASH上的object而建立起來的yaffs_object以外,在read_super執行過程中還會建立一些虛擬對象(Fake Object),這些Fake Object在NAND FLASH上沒有對應的物理實體,比如在建立文件目錄結構的最初,yaffs會建立四個虛擬目錄(Fake Directory):rootDir, unlinkedDir, deleteDir, lostNfoundDir分別用作根目錄,unlinked對象掛接的目錄,delete對象掛接的目錄,無效或零時數據塊掛接的目錄。
通過創建這些yaffs_object,yaffs文件系統就能夠將存儲在NAND FLASH上數據系統的組織起來,在內存中維護一個完整的文件系統結構
另外,我在看YAFFS2的源代碼的時候發現,YAFFS2再mount和umount和YAFFS有所區別,增加一個checkpoint機制,每次在 umount的時候,YAFFS2會開闢專門幾個block用來存取一些信息,等待下次mount的時候就不需要掃瞄整個flash,而只有找出這幾個塊 就可以了,這樣可以大大加速mount的時間。不過仔細的原理我也沒有研究過。有興趣的話可以看一看這封郵件http://www.aleph1.co.uk/pipermail/yaffs/2006q2/002019.html



我們用的硬件是omap平台,跑得是linux-2.4.21。其實在這個版本的源代碼裡已經有了mtd的支持。不過看一下代碼可以發現,這個版本 mtd驅動對nandflash的支持並不好,而且支持的最大的page不過512byte,可能是代碼比較早的原因吧。因此移植的第一步是更新mtd驅 動。
首先從mtd官方網站下載最新的cvs(好像只有支持ipV6的,才可以直接要連到cvs庫。或者去ftp下載)。不過好像最新的cvs代碼有一點問題, 我用得是mtd-snapshot20050519。解壓這個snapshot,然後是打補丁。相信這一步應該都什麼問題。打完補丁後,可以去 drivers/mtd/nand/看一看,會發現多了好多文件,其中最最重要的是nand_base.c,關於讀寫擦的流程都是這裡實現的。
接下來的事情比較關鍵,就是定義底層的讀寫端口,讀寫控制。我們可以仿照驅動裡提供spia.c,針對自己的硬件寫一個XXX.C。上層的代碼都已經做 好,都是一些函數指針,我們只要把我們自己特定一些函數掛上去就可以了。這一步說難也難,說簡單也簡單。一開始可能覺得無從下手,其實只要多讀幾遍 nand目錄下提供的很多的例子程序,就會有些思路了。寫完這個,就修改一下nand目錄下的MakeFile.common,如果你懶一點,可以把 spia替換你的XXX.o,到時候記得配置內核在mtd的nand下選擇spia支持就行。你要想做得規範一點,其實也簡單,首先在MakeFile裡 加上obj-$(CONFIG_MTD_NAND_XXX) += XXX.o。然後修改Config.in,加上對XXX的配置支持就可以了。
接下來就是按部就班的配置內核,編譯。如果沒錯,那麼恭喜你。不過一般會有錯,我碰到的是提示少了幾個頭文件。我在snapshot裡可以找到,然後一一拷貝的include/linux下就可以了,^_^
開始測試:
首先在內核啟動的時候,mtd會檢測硬件系統中是否有flash存在,這一步是通過讀取flash的ID來判斷。如果這一步是正常的,那麼說明底層驅動的 流程和硬件上是沒有錯誤了。很不幸,我在這裡就掛了。系統提示can『t kernel paging request at virtual address 0x0c000000,顯示了一大堆寄存器和堆棧就死在那裡了。好不鬱悶。google了好久,發現這一個是一個地址映射的錯誤。因為linux是分為內 核空間和用戶空間的。對於arm來說,內核空間的地址應該是3G-4G處,3G以下是用戶空間。而我在寫我自己的xxx.c文件的時候,IO端口是這樣設 置的
this->IO_ADDR_R = 0x0c000000;
this->IO_ADDR_W = 0x0c000000;
顯然0x0c000000是不屬於內核空間的,因此造成了上述問題。
因此我們要把讀寫命令端口映射到內核空間去,這便是虛擬地址。
this->IO_ADDR_R = (unsigned long)ioremap(0x0c000000, SZ_1K);
this->IO_ADDR_W = (unsigned long)ioremap(0x0c000000, SZ_1K);
因此要用ioremap()函數。這些函數都定義在include/arch/asm-arm/io.h
至於物理地址和虛擬地址應是如何映射的,mm.c有定義
好了,現在內核可以順利啟動了,flash可以順利的認出來了。嘿嘿,掃瞄了一下,還找出了幾個壞塊。
現在flash現在已經成為linux一種設備了。下面這兩條命令
mknod /dev/mtd0 c 90 0
mknod /dev/mtdblock0 b 31 0
把flash的第一個分區映射為字符設備和塊設備。mtd/util/提供了許多有用的工具,比如nandwrite,flash_erase等等。交叉編譯後就可以使用了。
flash_eraseall /dev/mtd0 把分區零的內容全部刪除。
隨便新建一個文件xxx,然後nandwrite -p /dev/mtd0 xxx。其中參數p表示允許填充。因為文件的大小不一定是flash的page的整數倍。
如果提示寫進去了,那麼基本沒問題了。我不放心,又用自己的測試程序在ccs裡測了一下,果然寫進去了。那真叫一個開心啊。迫不及待的mount -t yaffs2 /dev/mtdblock0 /mnt
提示:NAND:geometry problem chunk size is 2048 type is yaffs2
然後退出了mount進程。一盤冷水澆了下來,告訴我苦難的里程剛剛開始咯……



過來好久,才想起要寫,後來發現關於YAFFS2的移植,一些網頁上已經寫的很詳細了,於是就懶得寫了,不如寫幾個自己碰到的問題吧,自己感覺還是挺關鍵的問題。
問題一:地址映射問題(MTD測試階段)
描述:在系統啟動的時候顯示can『t kernel paging request at virtual address 0x0c000000
同時系統 kill init進程。無法啟動
解決:發現是沒有進行地址映射的問題
linux把地址空間分為用戶空間和內核空間,內核空間從3G開始,而物理地址0x0c000000並不屬於內核空間,直接使用就造成了上述問題。
因此我們要把讀寫命令端口映射到內核空間去,這便是虛擬地址。
修改xxx.c:
this->IO_ADDR_R = (unsigned long)ioremap(0x0c000000, SZ_1K);
this->IO_ADDR_W = (unsigned long)ioremap(0x0c000000, SZ_1K);
因此要用ioremap()函數。這些函數都定義在include/arch/asm-arm/io.h
至於物理地址和虛擬地址應是如何映射的,mm.c有定義
問題二:mount問題(YAFFS2測試階段)
描述:mount錯誤,失敗,提示:
NAND:geometry problem chunk size is 2048 type is yaffs2
解決:追蹤代碼發現問題在yaffs_guts.c裡,從代碼可以發現,mount時要求的分區的block數目要大於
dev->internalStartBlock + dev->nReservedBlocks + 2。而我mount的分區大小為一個block,因此不滿足條件。後來mount一個為4095個block的分區,成功。
問題三:文件消失(YAFFS2測試階段)
描述:mount上分區後,可以向/mnt/flash1上寫文件,也可以讀取。
但是umount 後,再mount發現文件消失。  
解決:這個問題幾乎鬱悶了我半個月,幾乎每天都在網上看YAFFS的mail list。一堆一堆的英文,看得都想吐了。到最後快絕望時候,才查了出來,原來最新的mtd中的nand_base.c代碼有問題。在 nand_write_ecc()中,沒有寫oob的內容(如果你選擇NAND_ECC_NONE)。而在yaffs的接口函數中在既有數據又有oob信 息的時候,是直接調用mtd->write_ecc()的。由於nand_write_ecc()沒有寫oob的原因,導致yaffs從oob讀取 信息時,讀到的全是0xff,從而無法構建文件系統。這是最最主要的一個umount後文件消失的原因,其實文件信息全寫進去了,只是tag信息沒有寫進 去。
    後來我把mtd換成了mtd-sanpshot20050519,這裡的nand_write_ecc()是寫oob信息的。就解決的umount的問題。
    好了,終於寫完了。關於YAFFS2的記憶要告一段落了。很感謝YAFFS2給我帶來這個終身難忘的暑假,88吧。


只能感嘆說,遷入系統愈來愈完整,看到以前人的辛苦

2012年3月12日 星期一

busybox目錄與檔案補齊

busybox一般編譯出來,真的精簡到可以,很多檔案目錄都缺orz,製作這些目錄跟檔案要下一堆指令,乾脆寫成script,這裡紀錄一下
話說~micro2440還真比不上BB,不過這價格就將就吧

2012年3月3日 星期六

新玩具完工~雲端投影片~

做了一個雲端投影的應用,弄了許久,終於搞定,這只是為了自己好玩開發出來的。也在網路程式上重新在上了一課,以前老是用高階的程式語言,開發的時候輕鬆許多,但很多時候也有許多限制,必須重新檢視網路的能力,再重新把Richard Steven的書翻出來,有了更深刻的體會,以前一些隱晦不明的地方,隨著對系統的了解也有比較深入的認知

比方以前很少去動到的socket option的設定,這次也用到了,因為在報告過程之中,一個socket可能會保留很久,預設的timeout時間太短了

setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout))

另外很多高階的程式語言其實無法很貼近系統,對於一些IPC的操作之類顯得比較無法做細部的調整,畢竟高階語言大多要跨平台,只能就共同的特性做對應

最後就是有些陷阱的部分,比方說使用24bits顯示模式,用程式抓下來的圖片最多不會超過24bits(很多人心裡應該會這樣默認吧),很可惜有些程式很好心的幫我們轉成了32bits,結果在解析圖片過程就可能造成錯誤

也遇到了一個無法解決的問題,那就是開發過程中因為程式的不正確讓connection若入的LAST_ACK的模式,但是client一直沒有反應,這時候即使把server的process殺了,port #還是會被綁住5~6mins之久,而且我也沒有找到解決方式,網路上大多釋放port #的方式是使用kill process的方式,對這個問題是沒有幫助的

2012年2月28日 星期二

"建構嵌入式Linux系統"讀後感

基本上真的是一本沒話說的入門好書了,作者是實作經驗豐富的人,所以中間穿插了很多實務上的考量與建議。如果想要讀這本的書人,建議先把linux開機流程看懂,讀起來更有概念,更輕鬆。此書稍微美中不足的只有整個偏重概念介紹,整體架構很好,但沒有完整的一個實例,可能讓人沒有從頭到尾操作的感覺,如果要體驗真的得找張板子好好實作一番

[好書推薦]建構嵌入式Linux系統(ch10, 11)

chapter 10提到了許多server架設的方式,也討論了許多必要注意的細節,很多部分端看應用
總結幾個重點:

  • Size does the matter. 有必要注重daemon的體積大小,不過也是看應用面,小記憶體就要小心,strip是個好幫手
  • 需要的library要拷貝到,編譯的時候要慎選library,可以省略不必要的lib,如果可以,考慮uclibc

作者大致上介紹了幾個常見的server,也提出了一些替代方案跟注意事項,我稍微簡介一下

  • SNMP : Net-SNMP用來建立SNMP-agent至於嵌入式裝置不錯
  • Telnet : utelnetd是個不錯的選擇,如果用uclilbc,記得加上termcap.h,可以是空檔案,另外裝置檔案記得要建立,如mknod /dev/ptmx c 5 2
  • SSH : dropbear是個替代方案
  • HTTP : bao或者thttpd
  • DHCP : udhp是一個替代方案,要記得加上udhcpd.leases檔案

現在愈來愈多的嵌入式產品其實已經開始使用web-GUI替嵌入式系統作為設定的介面(尤其是網路產品),所以我想如何把script language引入是一個必要的選擇

文章相當偏重實用以及經驗,所以實際編譯過應該比較有絕

chapter 11
文章中提到了一些除錯工具,最出名的當然就是gdb囉,還有一些系統的側寫(profile)工具,以及效能分析工具,gdb跟ptrace、strace網路上資料已經非常多,我個人經驗有限,就不再這裡野人獻曝了

最後幾章開始進入了即時系統的部分,放眼望去目前大多是一般的嵌入式系統,即時系統的部分比較少,等有遇到再說吧,看到這裡,可以把這本書蓋上了,有需要的時候再回來看

2012年2月27日 星期一

[好書推薦]建構嵌入式Linux系統(ch9)

很難讀懂得一章,無法完全理解U-boot是如何運作的,看了許久跟著在網路上爬文許久,突然領悟到了

u-boot的工作主要就是載入kernel,然後讓kernel去載入init這個process,這兩個元件主要都是放到記憶體。先說幾種主要的載入kernel的方式

  1. 由flash載入,最是單純,最好控制
  2. 由網路載入,蠻複雜的
  3. 由serial port載入,很龜速,主要依賴loadb/loadx/loady由serial port載入

以上幾個方式可以從底下網址找到(還有很多開機指令,需要看過一下,心裡有個底)
http://www.flatws.cn/article/program/shell/2011-02-23/14038.html

仔細觀察uboot提供的指令就可以理解到需要哪些環境變數,這些環境變數主要是記載了載入kernel的實體位置以及rootfs所在的地方

第一種載入的方式
必須先把kernel轉成為適當地格式,kernel一般會被壓縮成為zImage格式,然後在被變成uImage放置到flash的適當位址,這個位址被需傳給uboot讓他找到,跟著就是kernel的entry point位址,很不幸的書中沒說,直接跳到實際例子,我網路爬文許久終於找到

http://tech.ddvip.com/2008-09/122095341662350.html
http://sakbk.pixnet.net/blog/post/30892645-zimage-component

其中一段提到,在arch/arm/Makefile文件中的textaddr-y:= 0xC0008000这个是内核启动的虚拟地址,由編譯的核心裡面可以挖出來。我想這點也是之前網路教材沒寫出來,遇到的麻煩處(chapter 4)。在知道這個位址之後就剩下rootfs的位置需要被理解,比如是/dev/mtdblock4,這點在前兩三章有提到過

第二種由網路載入的方式
這個就頭大了,因為牽涉的東西往往很多,搞得我頭昏眼花,例如書中提到了如何建立NFS、DHCP 跟TFTP server就寫了一大段,這裡先跳過。接下來先看看開機指令
基本上就是經由TFTP Server載入kernel,然後在透過NFS server來掛載rootfs
用兩個指令達到這件事情
bootp:如何知道kernel image的位置是藉由DHCP server告知的,跟著uboot再去DNS server通知的地點利用tftp指令取回image
bootm:必須知道kernel第一條程式位址(entry address),如第一種方式提到
跟著就是設定一堆NFS相關的資料,讓uboot通知kernel如何去掛載rootfs,也就是書中看到的setenv bootnfs ... 那一堆龐雜的dscript

bootp還有變形的方式,也就是直接使用tftpboot 01000000 /data/kernel/virtex4-vmlinux-2.6.x.img表示直接透過tftp server將image抓回來放入ram 0100000的位址,這裡省略的DHCP的告知,但是就必須要事先設定好IP address,可以參考底下範例
http://blog.chinaunix.net/uid-20340721-id-1964603.html

第三種我就不介紹了,我也不打算使用:P不過如果有心的人應該看一下,哪天嵌入式系統被放到沒有網路的地方,剛好板子上面的flash又掛點,這時候只剩下你的NB跟serial port,這招看來就是最後一招了(還是可以用ICE解救??)

書中往往還教導使用如何將kernel寫到flash,還有如何編制uImage,如何架設server,讓整章看起來亂無章法,又一下子跳到實例應用,往往讓人十分迷惑

最後還有提到如何更新uboot跟image,還是不失本書一貫的風格相當精彩

最後附上其他參考資料
http://www.flatws.cn/article/program/shell/2011-02-23/14038.html
http://blog.xuite.net/chipinwu/blog/28718850-U+Boot%E7%9A%84%E9%85%8D%E7%BD%AE%E5%8F%8A%E7%B7%A8%E8%AD%AF
http://blog.udn.com/Howl0730/2663521
http://flykof.pixnet.net/blog/post/22975136-u-boot%E6%8C%87%E4%BB%A4

2012年2月26日 星期日

beagleboard xm的解析度設定

根據網站的spec寫的,他支援1280x720是可以的(再上去有問題,不過網路上印象中有人號稱hack了chip pin腳的信號,可以上到更高的解析度),但是很多人裝了ubuntu的image之後,解析度設定的問題一大堆,我自己本身也是,其實我猜應該是uboot的設定檔案讀取出了問題
很多設定為
1024x768MR-16@60
這樣之類的,我這樣設定也會出問題,最簡單的設定應該是
hd720
這個設定最沒有問題,他是1280x720MR-32@60,其他解析度呢?其實直接寫
1024x768@60
反而可以,但是如何設定16bits或者24bits我倒是不知道了(這個預設為32bits)

[好書推薦]建構嵌入式Linux系統(ch8)

這個章節作者談到了各種rootfs的type,也就是要使用ext2、ext3、cramfs、squashfs、JFFS2、tmpfs哪一種,每一種都有它的特色
為了執行方便,在開發完成rootfs的時候會將他們壓縮成image或者其他格式,再載入的時候,再由kernel指示CPU該檔案解開並且掛載成root directory
另外介紹了兩種常用來拷貝rootfs到需要的地方(比方說成為image),這兩個公用程式分別是dd以及cpio,兩者都是低階壓縮工具,dd很適合將整個partition拷貝到另外一個地方,比如另外一個partition,cpio則是連device file都能拷貝
geneextfs -b 1024 -d rootfs -D device_table.txt -e 0 initrd.img
gzip -9 < images/initrd.img > images/initrd.bin
第一行先產生一個ext2的image跟著第二行將image壓縮成ramdisk
cd ${PROJECTDIR}/rootfs
find . | cpio -o -H newc | gzip > {PROJECTDIR}/initramfs.cpio.gz
這樣kernel會把這個檔案已tmpfs的格式放到ramdisk下執行
書本中還提到了許多跟實務上有相關的選擇標準,礙於個人接觸太少,只好先"記帳":P
最後做整提到了更新的問題,更新的情況也會影響rootfs type的選擇,另外就是如何處理更新的過程,有三個作者提到的基本工具 : cpio、rsync以及dpkg

2012年2月25日 星期六

[好書推薦]建構嵌入式Linux系統(ch7)

這一章節講到Memory Technology Device (MTD),主要針對Nor flash跟Nand flash作說明,因為這兩者是經常被使用在遷入系統的對象
在編譯核心的時候必須要將兩者需要的driver編譯進入模組(在menuconfig中的Device Drivers=>MTD Support=>...這些項目)
作者也提供了一系列操作MTD的工具程式,如一般工具
flash_info、flash_erase、flash_unlock、flash_ereaseall、flash_lock、flashcp、doc_loadbios、mtd_debug
FTL(flash translation layer)與NFTL(nand FLT)工具
ftl_format、ftl_check、nftl_format、nftldump
如何格式化成適當地檔案格式(jffs與jffs2)
mkfs.jffs2、sumtool、jffs2dump
另外重要的就是如何分割flash這類的MTD,因為很有可能就是要將檔案系統等等資料寫入這個地方。在操作上linux大致上將一切裝置看成檔案,而所有檔案大致上分為兩類block以及character,所有的裝置必須在/dev底下可以被找到
所以除了如何利用工具分割flash之外就是如何用mknod建立適當地裝置,給予primary number與secondary number
目前比較沒有感覺,如果等到講到bootloader以及如何在裝置上面燒錄bootloader、kernel跟rootfs應該會比較有意義

2012年2月24日 星期五

[好書推薦]建構嵌入式Linux系統(ch6)

作者介紹了一個rootfs需要的各個目錄
目錄內容
bin使用者指令
bootboot loader的靜態檔案
devdevice files
etc設定檔
home使用者家目錄
lib程式庫
media可移除掛載點
mnt暫時性的掛載點
opt附加軟體套件
proc核心行程資訊與虛擬檔案系統
rootroot home目錄
sbinroot使用的指令
sys系統資訊以及控制的虛擬檔案系統
tmp暫時性檔案
usr第二層目錄包含對大多使用者的應用程式與文件,包含X server
varlog,與公用程式的變動資料

依照作者的說法有許多目錄可以省略,但我倒是抱持著相反看法,雖然很多目錄不實用(依照應用可省略),但是如果只是空的目錄應該是不占用空間,放著應該也不至於佔據太大的空間。

跟著提到了拷貝必要的libs進入rootfs之中,他列出了兩個重要的script可以拷貝需要的static & dynamic library

接著提到核心module的拷貝跟kernel image,其實作者也提到kernel image會不會進入rootfs跟bootloader有關,以現在很多小型的記憶體裝置或者flash memory,應該都還是有可能不會進入rootfs

跟著作者相當程度的介紹了/dev跟/udev底下的功能以及設定,尤其是udev,這是一個在2.6後引入的hotplug以及新的系統控制的目錄,相當重要,想來未來會愈來愈吃重,必須仔細詳讀。

最介紹到了系統初始化的啟動程式init以及其他的應用程式(只的是一般常用的公用程式如ls之類),這時候又介紹了一個重要的project,名為busybox,以體積小著稱,他同時包含了公用程式以及init的腳色,相當適合使用在遷入系統


2012年2月23日 星期四

LCD之framebuffer(3)

還沒深入了解framebuffer之前,我實在意想不到每次在framebuffer(fb)"作畫"都會有些小瑕疵,因為如果是在X-win,大概很快的x-win的東西就會蓋過fb的內容,變得難看,在tty底下則是會面臨那個閃爍游標的問題

取消或者使用cursor blink功能
echo 0 > /sys/class/graphics/fbcon/cursor_blink
如果是1表示enable,而0表示disable

另外一個問題是sleep mode
取消lcd sleep mode(可是有時候沒這個檔案)
echo 1 > /sys/class/graphics/fb0/blank
透過一些操作來達成
echo -e '\033[9;X]' > /dev/tty1

參考資料
http://www.armadeus.com/wiki/index.php?title=FrameBuffer

2012年2月22日 星期三

[好書推薦]建構嵌入式Linux系統(ch5)

這章說的是核心(kernel)編譯
第一步是挑選核心,看是要使用哪個版本,包含考慮到硬體的考量,畢竟核心是對硬體提供了好一些driver,以及提供了各種記憶體管理、排程等功能

編譯核心的過程大致上分成幾個

  1. 設定congfigure
  2. 依照平台編譯
  3. 編譯模組 (modules)
  4. 安裝核心
  5. 安裝模組
  6. 測試核心

編譯的時候需要先設定configure

  • make config : 依次要求使用者設定
  • make oldconfig : 載入舊的設定檔案
  • make menuconfig : 使用curses建構的window設定
  • make xconfig : 使用x-win

除了第二個,基本上另外三個是一樣的,但是推薦使用make menuconfig,因為config在設定時候太麻煩,xconfig則需要x-win,且效果未必比menuconfig好
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
ARCH指定CPU,CROSS_COMPILE則是toolchain的名稱,千萬別傻傻跟我一樣打成CROSS-COMPILER,這樣會發稱慘案,請參考我之前編譯busybox的時候
另外作者提到一個重要的變數EXTRAVERSION,其實就是字面上的extra-version,嵌入式系統有時候會需要用上自己特殊的設定,這個變數指定最後的postfix,讓人辨別編譯出來的版本如2.6.20-motor-diff

編譯核心相對應單純
make ARCH=arm CROSS_COMPILE=arm-linux- zImage
系統會產生出vmlinux檔案,這是尚未壓縮的,zImage是使用bizp2壓縮過的,bzImage則是讓產生的壓縮檔案格式允許超出512KB,對應於硬體的限制

編譯模組也是蠻單純的
make ARCH=arm CROSS_COMPILE=arm-linux- modules
如果需要清除之前設定
make ARCH=arm CROSS_COMPILE=arm-linux- distclean


安裝核心與安裝模組
安裝核心比較單純,只要拷貝四個檔案vmlinux、System.map 、設定檔案(.config)跟bzImage/zImage,他們會位在arch/arm/boot/目錄底下。模組要小心處理,不能安裝到host機器中,不然可能會有危險
make ARCH=arm CROSS_COMPILE=arm-linux- INSTALL_MOD_PATH=${PROJROOT}/images/modules-2.6.20 modules_install
將module放到第四章提到的相對應目錄內

最後就是測試的部分,作者也沒給出太多建議,不過倒是有提到一個有趣的議題就是kernel panic的處理函式panic(),有些機器可以直接重新開機,有些則必須額外處理,相對應於應用跟規劃,例如火災的感知器如果有異狀,產生kernel panic,我想馬上產生一個警報(即使是假警報)也好過重新開機,因為重新開機有可能在當機,延誤了火災的救援