嵌入式Linux開發板常見問題

華恆ColdFire系列嵌入式Linux開發板常見問題解答
——基於公用核心板HHCF5249/5272
(華恆科技版權所有)
1、關於宿主機Linux的安裝
建議使用REDHAT系列:建議選擇完全安裝,即選擇Custom,然後在Package中選擇everything。
【以下配置詳見最新PDF手冊下載(例如:HHCO5272-R1的手冊)】

宿主機的網絡配置
主要是要安裝好以太網卡,對於一般常見的RTL8139網卡,REDHAT7.2可以自動識別並自動安裝好,完全不要用戶參與,因此建議使用該網卡。然後配置宿主機IP:
ifconfig eth0 192.168.2.32
【注意】
對於REDHAT7.2,它默認的是打開了防火牆,因此對於外來的IP訪問它全部拒絕,這樣其它網絡設備根本無法訪問它,即無法用NFS mount它,無法通過TFTP從它下載,無法telnet,ftp它等。因此網絡安裝完畢後,應立即關閉防火牆。操作如下:
運行setup,選擇Firewall configuration,選中No firewall。然後到上一層菜單選擇System services,去掉ipchains和iptables兩項服務。最後退出setup。
其實,在安裝REDHAT7.2/3時,就要求選擇Custom定製安裝,其中由一項就是要求選擇No Firewall,這樣的話,啓動後,就不需要執行setup來設置防火牆了。還有,REDHAT在這裏有個BUG,即無論上次你進入Firewall configuration選擇什麼,每次再次進入時它都顯示High,這是REDHAT顯示的BUG,其實防火牆已經關閉了。

配置NFS
運行linuxconf,在config選項下選Server tasks,選中Exported File systems(NFS),然後選擇Add Directory,加入根目錄/,然後Accept。系統就會輸出根目錄允許NFS mount。
下一步再選擇Control項下面Control panel下的Control Service activity,然後選擇nfs enabled,然後start。配置好後的界面顯示其中nfs必須爲: Automatic Running。
【注意】
這裏建議把ipchains和iptables都取消其自動啓動的狀態。
最後,在Control項下面Control panel下選擇Activate configuration,則彈出界面,提示系統配置的改動,選擇"Do it",最後退出時則完成NFS配置。
配置完成後,可用如下辦法簡單測試一下NFS是否配置好了:
在宿主機上自己mount自己,看是否成功就可以判斷NFS是否配好了。例如在宿主機/目錄下執行:
mount 192.168.2.32:/ /mnt
然後到/mnt/目錄下看是否可以列出/目錄下的所有文件和目錄,可以則說明mount成功,NFS配置成功。 

配置TFTP服務器 
參見下面第二點介紹。
【注意】
安裝完華恆uClinux軟件光盤後,不要make xconfig,直接make即可。加入驅動等修改內核的操作都不必make xconfig,除非要更改處理器平臺,例如移植到MCF5407等才需要make xconfig。其實這個操作不過就是修改linux/.config和linux/include/linux/autoconfig.h中的宏設置。完全可以由手工完成。

2、關於gdbtftpflash燒寫
【注意】
燒寫必須接百兆以太網接口,對於多以太網板的10M口是不能用來燒寫的。
在一個Linux TTY終端執行
./flash
然後立刻切換到另一個TTY終端啓動的minicom下去查看信息
Reading image.bin from 192.168.2.46 to 0x00100000
TFTP download successful
或者信息如下:
ICMP: Port unreachable
ICMP: Port unreachable
ICMP: Port unreachable
TFTP could not make connection to server
Errors in TFTP download

Read 1004740 bytes (1963 blocks)【這纔是關鍵所在,前面的信息都無用,只要這裏讀到的字節數和宿主機上/tftpboot/目錄下的image.bin文件的大小一致就表明TFTP下載成功了!】
>>>>>>>>>> Init mflash
>>>>>>>>>> Init mflash Successfully
********** File size : 0xF54C4 bytes
********** Address base : 0x0
********** Manufacturer ID 1
********** Device ID 2249
********** Sector 0 [FFC00000] (0-unprotect, 1 protect):0
********** Sector 1 [FFC04000] (0-unprotect, 1 protect):0
********** Sector 2 [FFC06000] (0-unprotect, 1 protect):0
********** Sector 3 [FFC08000] (0-unprotect, 1 protect):0
********** Sector 4 [FFC10000] (0-unprotect, 1 protect):0
********** Sector 5 [FFC20000] (0-unprotect, 1 protect):0
********** Sector 6 [FFC30000] (0-unprotect, 1 protect):0
********** Sector 7 [FFC40000] (0-unprotect, 1 protect):0
********** Sector 8 [FFC50000] (0-unprotect, 1 protect):0
********** Sector 9 [FFC60000] (0-unprotect, 1 protect):0
********** Sector 10 [FFC70000] (0-unprotect, 1 protect):0
********** Sector 11 [FFC80000] (0-unprotect, 1 protect):0
********** Sector 12 [FFC90000] (0-unprotect, 1 protect):0
********** Sector 13 [FFCA0000] (0-unprotect, 1 protect):0
********** Sector 14 [FFCB0000] (0-unprotect, 1 protect):0
********** Sector 15 [FFCC0000] (0-unprotect, 1 protect):0
********** Sector 16 [FFCD0000] (0-unprotect, 1 protect):0
********** Sector 17 [FFCE0000] (0-unprotect, 1 protect):0
********** Sector 18 [FFCF0000] (0-unprotect, 1 protect):0
********** Sector 19 [FFD00000] (0-unprotect, 1 protect):0
********** Sector 20 [FFD10000] (0-unprotect, 1 protect):0
********** Sector 21 [FFD20000] (0-unprotect, 1 protect):0
********** Sector 22 [FFD30000] (0-unprotect, 1 protect):0
********** Sector 23 [FFD40000] (0-unprotect, 1 protect):0
********** Sector 24 [FFD50000] (0-unprotect, 1 protect):0
********** Sector 25 [FFD60000] (0-unprotect, 1 protect):0
********** Sector 26 [FFD70000] (0-unprotect, 1 protect):0
********** Sector 27 [FFD80000] (0-unprotect, 1 protect):0
********** Sector 28 [FFD90000] (0-unprotect, 1 protect):0
********** Sector 29 [FFDA0000] (0-unprotect, 1 protect):0
********** Sector 30 [FFDB0000] (0-unprotect, 1 protect):0
********** Sector 31 [FFDC0000] (0-unprotect, 1 protect):0
********** Sector 32 [FFDD0000] (0-unprotect, 1 protect):0
********** Sector 33 [FFDE0000] (0-unprotect, 1 protect):0
********** Sector 34 [FFDF0000] (0-unprotect, 1 protect):0
xxxxxxxxxx Program sector 0 : Read Fill Erase Program End
xxxxxxxxxx Program sector 1 : Read Fill Erase Program End
xxxxxxxxxx Program sector 2 : Read Fill Erase Program End
xxxxxxxxxx Program sector 3 : Read Fill Erase Program End
xxxxxxxxxx Program sector 4 : Read Fill Erase Program End
xxxxxxxxxx Program sector 5 : Read Fill Erase Program End
xxxxxxxxxx Program sector 6 : Read Fill Erase Program End
xxxxxxxxxx Program sector 7 : Read Fill Erase Program End
xxxxxxxxxx Program sector 8 : Read Fill Erase Program End
xxxxxxxxxx Program sector 9 : Read Fill Erase Program End
xxxxxxxxxx Program sector 10 : Read Fill Erase Program End
xxxxxxxxxx Program sector 11 : Read Fill Erase Program End
xxxxxxxxxx Program sector 12 : Read Fill Erase Program End
xxxxxxxxxx Program sector 13 : Read Fill Erase Program End
xxxxxxxxxx Program sector 14 : Read Fill Erase Program End
xxxxxxxxxx Program sector 15 : Read Fill Erase Program End
xxxxxxxxxx Program sector 16 : Read Fill Erase Program End
xxxxxxxxxx Program sector 17 : Read Fill Erase Program End
xxxxxxxxxx Program sector 18 : Read Fill Erase Program End
********** Verify Complete
下面板子開始重啓。
【注意】
一定要看到這些Read Fill Erase Program End信息才表示燒寫進去了,前面
********** Sector 0 [FFC00000] (0-unprotect, 1 protect):0等只是顯示FLASH的扇區分佈,
並沒有進行燒寫,只有看到Read Fill Erase Program End信息才表示在進行燒寫。 
在minicom中用ctrl+a,然後按b,接着用上下箭頭,可以翻看前面的信息,從而查看出了什麼錯誤。例如,TFTP連接失敗的信息就要前翻來查看,信息如下:
Unable to locate 192.168.1.46
Errors in TFTP download.
Read 0 bytes (0 blocks)
這就要查看宿主機(即TFTP服務器配置是否成功)。

工作機制:
./flash調用hhco.gdb腳本對CPU進行初始化,(sys-init)
然後指定
target bdm /dev/bdmcf0
load 即下載一個小軟件(tftp.elf,約80K)到板子的RAM中,並用c(continue)命令讓它跑起來,這時CPU完全由這個小軟件接管。這個小軟件跑起來後初始化以太網及TFTP協議棧,然後它運行TFTP客戶端,從內存中0x00200004(2M+4處)讀取gdb腳本放在此處的TFTP服務器IP地址,並從該IP的TFTP服務器PC下載image.bin到板子內存1M地址處,再將其燒寫到FLASH上,重啓板子,這時引導起來的就是LINUX了。

問:燒寫完畢後最後會報如下錯誤:
Program received signal SIGBUS, Bus error.
0x488 in asm_exception_handler ()
1: x/i $pc 0x488 <asm_exception_handler+4>: orib #84,%d0
注意上述信息並非錯誤,燒寫完退出時都要顯示這個信息,並不能表示燒寫是否成功。燒寫成功與否完全要看minicom端的顯示信息來判斷。

問:運行./flash時報錯,內容如下:
./gdb:error while loading shared libraries:libncurses.so.4:cannot load shared object file:No such file or directory.
這是怎麼回事呢?
答:這是由於宿主機REDHAT安裝時不完全,不支持DEVELOPMENT工具,如gcc,gdb等工具,導致系統沒有安裝運行這些工具所需的共享庫。建議重新完全安裝系統。

3、 關於TFTP服務器設置

其實TFTP服務器可以是和板子相連的局域網內任意一臺開通了TFTP服務的LINUX PC機,即板子可以從任意一臺TFTP服務器下載IMAGE文件並進行燒寫,當然首先要檢查IP是否匹配及連線是否正確。但若將LINUX宿主機(即用串口線連接的那一臺LINUX PC)同時開通TFTP服務,這樣就不必佔用多臺機器。默認完全安裝後的REDHAT的TFTP服務是沒有開通的,要自己手工開通。
開通宿主機上的TFTP服務,對於REDHAT6.x,可以在宿主機上:
vim /etc/inetd.conf
查找tftp,若發現前面有#就表示這一行被註釋掉了,即服務沒有打開,去掉#就打開了TFTP服務,然後重啓宿主機即可。
對於REDHAT7.2,則在宿主機上執行setup,選擇System services,將其中的tftp一項選中(出現 [*]表示選中),並去掉ipchains和iptables兩項服務(即去掉它們前面的*號)。然後還要選擇Firewall configuration,選中No firewall。最後,退出setup,執行如下命令以啓動TFTP服務:
service xinetd restart
配置完成後,建議簡單測試一下TFTP服務器是否可用,即自己tftp自己,例如在宿主機上執行:
cd /
cp /HHCO5272-R1/image/image.bin /tftpboot/
tftp 192.168.2.32
tftp>get image.bin
若出現如下信息:
Received 634732 bytes in 0.7 seconds
就表示TFTP服務器配置成功了。若彈出信息說:Timed out,則表明未成功,需要按照上述步驟重新檢查一遍。
或者用如下命令查看tftp服務是否開通:
netstat -a|grep tftp
完成上述配置工作後,就可以開始使用該以太網燒寫工具了。

4、BDM與重啓問題
安裝bdm驅動模塊,以HHCO5272-R1爲例:
1. cd HHCO5272-R1/bdm
2. insmod linux-bdm.o 【可將此句寫入/etc/rc.d/rc.local文件中,如:
/sbin/insmod /HHCO5272-R1/bdm/linux-bdm.o,這樣每次PC啓動都會自動執行,否則每次啓動宿主機都要執行這一句】
3. ./MAKEDEV 【在/dev/下創建設備bdmcf0,只要執行一次】
【注意】
在insmod時有可能出現.o文件與內核版本不匹配現象,這時只要重編該模塊驅動即可。具體請參閱下面第31條。
還有,BDM線的長度不能加長,否則使用時會報"bdm not open"。

問:板子剛拿到,一加電就不啓動,運行指示燈不閃,minicom什麼信息也沒有,怎麼回事?
答:這是因爲插了BDM卡,若不插BDM卡,板子就可以正常啓動了。
從軟件使用者的角度來說,插了BDM後,核心板的reset鍵就失效,所以板子加電後沒有收到reset信號,所以板子不能啓動。這時要板子讓板子上的軟件系統啓動運行,可以先執行一下chk,然後立刻退出則板子就會自動重啓。
cd chk
./chk
>>>x
當板子啓動後,可以通過minicom接收命令,則要重啓就直接在minicom下鍵入reboot即可重啓,這時按reset鍵無效。若不插BDM則板子的reset按鍵是有效的。
有時,,執行chk時報錯:
device busy表示有其它程序在使用BDM
用ps -A
看看是否有其它程序在使用BDM,例如gdb(即gdbtftpflash下的./flash)或者chk,
若提示device not found,則表明沒有安裝驅動linux-bdm.o

5、板子死了?
判斷板子是否死機的標準不是minicom是否可以輸入等,最可信的標準就是看核心板上的運行指示燈是否還正常的閃爍,若不再閃了,必死無疑。有時串口可以打印輸出信息,但用戶卻無法輸入命令,這經常是由於操作者手上靜電太高導致串口工作異常。這時建議給板子斷電,把核心板和底板以及串口線等都重新拔插一下再加電重啓試試;或者換一臺PC,或者用telnet使用網絡終端。

6、TFTP下載與RAM版本問題

用bootloader下載RAM內核,總是報錯:
KERNEL: Bad trap from supervisor state, vector=4
CURRENT PROCESS: 
COMM=swapper PID=1 
TEXT=00100000-00156e6c DATA=00000000-0016685c BSS=0016685c-0017d7f0 
USER-STACK=00000000 KERNEL-STACK=0021d000
......
答:
因爲TFTP採用的是udp傳輸的,
而我們的板子是通過一個小HUB跟局域網聯在一起的,
可能在傳輸中有些包丟失了,或者是在傳輸中有些
數據出現錯誤,因此出現RAM版的不能用。後來單獨把板子跟一臺計算機的網卡相連,
或者都接到同一個HUB上,就不會有問題了。
有時燒寫完後板子啓動時回出現如下錯誤:
Unable to open an initial console.
這種現象有多種原因可能導致出現,其中就有可能是這裏所提的燒寫錯誤所致。

7、BUSS ERROR的問題
記住出錯時打印出的PC指針值,將linux/linux
用m68k-elf-objdump -D linux >tt
vim tt
反彙編後查看該PC地址處在什麼函數調用內,
從而作進一步定位。
用chk單步跟蹤,(fp命令)
建議閱讀chk源代碼,可以根據自己的需要定製自己的調試命令。
所有可用的BDM操作都在bdm/下的一個bdm.h文件中。

8、硬件擴展
問:CN5的複用腳p19,p23,p25是系統寬度總線控制信號,留給 用戶,系統沒有用嗎?那麼復位期間如何確定總線寬度?
回答:上電的時候作爲系統寬度總線控制信號;但是上電結束開始運行之後,就變成SPI信號線了,您可以使用。問:普通usb口只用d+ d_兩條信號線,而5272增加了轉出去的信號線:usb-rp,usb-tp....(pa{6:0}),用戶能否用其第一功能?
回答:5272本身帶有usb收發器,5272可以讓您選擇是否選擇外部usb收發器(通過配置內部寄存器來選擇)。建議選用外部USB收發器。注意!是收發器,不是控制器!USB控制器是在5272裏面的。
【注】cn5,cn6只是做簡單的擴展,而你可以通過自己設計底板(華恆底板都已經在手冊裏面有原理圖了!),從而在cn1,,cn2,cn3使用信號。cn1,cn2,cn3上的管腳對應的信號原理圖上都有。其中地址線在cn1的1~45(奇數腳),數據線在cn2的2~64(偶數腳)。ddat[3:0]和DTEA都在cn3上,是用於接BDM口的。具體使用請參考5272處理器手冊。
USB[3:1]管腳是從一個外接的USB收發芯片pdiusb11上接出的。而TX_P~RX_N是以太網隔離變壓器的輸出線。cpuclk的頻率爲66Mhz,無驅動。

關於系統I/O:
MCF5272共提供48個通用IO引腳,它們可以分爲3個16位PORT,即PORTA、PORTB、PORTC。其中PORTA,PORTB對應的控制寄存器來實現與其它信號引腳的複用。Port C沒有PCCNT寄存器,它只能在工作爲外總線16位模式時作爲16位的I/O口線使用,即它與D[0~15]複用,只有16位外總線模式時,因爲只用高16位D[16~31],這時D[0~15]就爲PC[0~15]。另外的一個端口Port D不能被用做I/O線。
系統剩餘GPIO資源(以HHCO5272-R1爲例):
PA7~PA14(8根引腳);PB4~PB7(4根引腳);
若去掉USB接口,則PA[6:0]可用(7根引腳)。
所以一般的去掉USB,通用IO引腳可用的有8+4+7=19根。
串口0所佔用的PB[3:0](4根引腳),其中PB0/1爲URT0_TxD/URT0RxD,PB2/3爲CTS/RTS。
若去掉串口0的CTS/RTS,又多2根,即可19+2=21根。
若整個去掉串口0,又多兩根,即最多21+2=23根。

9、串口2檢測
將板子的串口2和宿主機的串口1連接起來,在宿主機的一個TTY啓動minicom,另一個TTY執行chk
./chk
>>>fr colilo2.bin e00000 【下載到RAM中0x00e00000地址處】
>>>fg xx e00400 【從0x00e00400地址處開始執行,加上0x400是要跳過前面1024個字節的ramvect】
代碼下到板子RAM中,然後用fg將其激活跑起來後,CPU就由那個代碼控制了,這時就不要在chk中輸入任何命令了。不要在chk中執行退出(x),否則板子立即reset,下載到RAM中的內容就丟了。【注意】沒有fg之前,核心板上運行指示燈(LEDK1)是不亮不閃的。一旦fg xx e00400後就應該亮閃起來。這是判斷下載軟件是否跑起來的唯一標準,與串口是否打印完全無關。若minicom沒有打印信息,就只能說明串口2是壞的。

10、開發/使用注意
◇無論編譯內核還是自己的某一個應用程序都必須在uClinux目錄下進行編譯make,在其它目錄下編譯都會報錯。◇當板子插了網線時,核心板上的百兆以太網連接和碰撞指示燈(LEDL2)就會亮起來,若這時板子ping一臺PC機或者一臺PC機ping板子的話,LEDL2燈就會閃爍起來。若LEDL2不亮,可能是以太網插口接觸不好所致,用力插緊即可。
◇HHCO5272-R1提供了串口2可用於作MODEM撥號,需要把uClinux/user/pppd/、chat/和diald/三個目錄加入編譯,並編寫正確的撥號腳本和配置文件。華恆提供完備的PPP撥號軟件包。
◇HHCO5272-R1板上採用的是ROMFS的文件系統,它是隻讀的。可以擴展支持JFFS/JFFS2文件系統,它可讀可寫。華恆提供完備的JFFS/JFFS2支持軟件包。
◇在用ddd-5272調試應用程序時,若看不到代碼,是因爲沒有加-g的編譯參數;若代碼能看到,但是是在run的時候提示BDM not Open! 這是run命令的問題,運行時不要用run,而用continue命令,即c。
◇MCF5272不支持外設的DMA,它只有內部DMA,爲FEC所用。
◇要在系統啓動時自動執行用戶自己的應用程序,就必須修改uClinux/romfs/etc/rc文件,這是個啓動的腳本文件,它的作用就相當於WINDOWS98下的autoexec.bat,這個腳本文件中的每一句都是在shell下可直接執行的命令。例如用戶移植了WEB SERVER boa,要啓動就執行boa,就在這個rc文件的最後加一句boa&,然後到uClinux下執行make,然後./flash燒寫板子即可。
◇板子IP的修改:
可以用ifconfig/route(2.4內核不需要route命令)命令來修改板子啓動後的IP,但這個修改在重啓後無法保存。因爲板子IP的指定是在其ROMFS文件系統的/etc/rc文件中指定的,如下:
ifconfig eth0 192.168.2.112
route add -net 192.168.2.0
要永久的改變板子的IP,就要在宿主機上修改uClinux/romfs/etc/rc文件中對應的IP設置內容,然後在uClinux下重新編譯,然後重新燒寫。但這樣做的問題在於無法做到動態修改IP並保存。要實現這種功能,就必須在板子上實現文件存儲功能。實現的機制有許多,如flatfsd、JFFS/JFFS2文件系統等。對於板子上的存儲機制,華恆提供完整的JFFS/JFFS2軟件包銷售,可大大加快用戶的開發進度及產品上市時間。

11、啓動失敗
客戶問:HHCF5272-LCD-IDE-R1套件中:把image.bin寫到flash後,應該可以從板子啓動進入uClinux中,但是它會出現一個錯誤是kernel panic attempted to kill init!
答覆:都是usb_init惹的禍
這樣修改:
vim uClinux/linux-2.4.x/drivers/char/mem.c
去掉usb_init一行,然後重新編譯燒寫就沒有問題了。

12、串口2問題 
◇客戶問:
一個簡單測試程序,向/dev/ttyS0發送數據,波特率設爲38400,在PC機下順利接收到。利用5272開發板上的串口1發送,另一端在minicom下,設爲相同的波特率,能接收到數據,但是相同的程序,只修改爲/dev/ttyS1確收不到任何數據,
答覆:經次測試,發現是缺少了對串口2佔用的PD口的初始化。
對於HHCF5272-R1,更新的文件sysinit.c,
將它覆蓋到uClinux/linux/arch/m68knommu/platform/5272/目錄下,
重新編譯燒寫即可。
對於HHCF5272-LCD-IDE-R1 ,將附件colilo.bin覆蓋到uClinux/colilo/目錄下,重新編譯燒寫即可。

13、擴大RAM盤的方法
有客戶問到增大HHCF5272-R1板子上的/var/目錄大小的問題,
這個目錄是RAM盤,可讀可寫。
它的大小是在uClinux/romfs.mk中指定的:
例如要指定爲2M大小的RAM盤:
則加入如下一句:
RAMFSy = $(USER)/ramimage/ramfs2048.img
即可。
【注意】
RAM盤太大好像會引起系統死機。

14、關於編譯重燒啓動時出現“unable to open an initial console”問題
解決辦法:
修改uClinux/vendor/HHtech/M5272/Makefile,
將其中的genromfs改爲/usr/local/bin/genromfs即可。

15、關於BDM驅動“ kernel-module version mismatch”問題
現象:在bdm/driver/linux下執行make後,insmod linux-bdm.o時出現如下錯誤:
linux-bdm.o: kernel-module version mismatch
linux-bdm.o was compiled for kernel version 2.4.17
while this kernel is version 2.4.5. 
解決辦法:
1、要註釋MODVERSIONS=-DMODVERSIONS
即:#MODVERSIONS=-DMODVERSIONS
2、修改bdm/driver/linux/Makefile中的CFLAGS一行爲如下:
CFLAGS = -Wall -g -O -pipe -I/usr/src/linux-2.4/include -I.. -DMODULE -D__KERNEL__ $(MODVERSIONS)
這樣編譯就不會有內核版本不匹配的問題了

16、關於系統啓動時數據總線寬度的問題
5272複用腳L5 QSPICLK/BUSW1 和M5 SPI_CS0/BUSW0
在HHCO5272-R1中用作 QSPICLK 和 SPI_CS0 功能(CN1 
pin93 ,CN1 pin95) , 而只有在CPU復位時它們才作爲BUSW1:BUSW0組合決定CS0內存數據寬度。這個是不需要配置的。
具體參見MCF5272手冊:P14-2頁,即P14.3.1節介紹。
華恆板子的BUSW1:BUSW0組合爲[1:0],即16位模式,因此剛加電時接CS0的FLASH0的數據總線寬度爲16位模式。
同理,N4 QSPI_DOUT/WSEL 在HHCO5272-R1中用作 
QSPI_DOUT 功能(CN1 pin89 ), 
WSEL也只是CPU復位時生效,華恆板子此腳接下拉電阻,表示爲0,因此爲32位模式。此後都作爲QSPI_DOUT信號使用,不需配置。

17、關於REDHAT7.3/8.0/9.0等高版本宿主機上NFS配置的問題
目前主要的問題在於完全安裝的這些REDHAT版本沒有提供linuxconf工具軟件,因此無法配置NFS服務器。不過這個問題很容易解決,這需要到http://ftp.boe.tcc.edu.tw/tnc/firewall/下載一個名爲:linuxconf-1.25r7-3.i386.rpm的RPM包,然後在REDHAT LINUX機器上執行:
rpm -i linuxconf-1.25r7-3.i386.rpm (6,995KB)
這個安裝比較耗時,安裝完畢後,立即就可以使用linuxconf工具了

18、關於定時器使用的問題
對於秒級以上的應用程序:
alarm(sec)
在sec秒以後就會產生一個sigalrm信號。
註冊一個自己的處理函數來處理這個信號就可以實現。
對於ms級的定時,usleep爲us級的延時,但無法提供中斷。
MCF5272提供四個定時器,uClinux只使用了其中一個:
uClinux/linux/arch/m68knommu/platform/5272/config.c中:
void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *))
{
volatile unsigned short *timerp;
volatile unsigned long *icrp;
/* Set up TIMER 1 as poll clock */
timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1);
timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE;
timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ);
timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
*icrp = 0x0000d000; /* TMR1 with priority 5 */
request_irq(69, handler, SA_INTERRUPT, "ColdFire Timer", NULL);
}
void config_BSP(char *commandp, int size)
{
memset(commandp, 0, size);
mach_sched_init = coldfire_timer_init;
mach_tick = coldfire_tick;
mach_trap_init = coldfire_trap_init;
}
uClinux/linux/arch/m68knommu/kernel/time.c:
void time_init(void)
{
unsigned int year, mon, day, hour, min, sec;
extern void arch_gettod(int *year, int *mon, int *day, int *hour,
int *min, int *sec);
arch_gettod (&year, &mon, &day, &hour, &min, &sec);
if ((year += 1900) < 1970)
year += 100;
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
if (mach_sched_init)
mach_sched_init(timer_interrupt);
}
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
{
/* last time the cmos clock got updated */
static long last_rtc_update=0;
/* may need to kick the hardware timer */
if (mach_tick)
mach_tick();
do_timer(regs);
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
xtime.tv_usec < 500000 + (tick >> 1)) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
}
add_timer函數在uClinux/linux/kernel/sched.c中定義
void add_timer(struct timer_list *timer)
{
unsigned long flags;
save_flags(flags);
cli();
#if SLOW_BUT_DEBUGGING_TIMERS
if (timer->next || timer->prev) {
printk("add_timer() called with non-zero list from %p\n",
__builtin_return_address(0));
goto out;
}
#endif
internal_add_timer(timer);
#if SLOW_BUT_DEBUGGING_TIMERS
out:
#endif
restore_flags(flags);
}
static inline void internal_add_timer(struct timer_list *timer)
{
/*
* must be cli-ed when calling this
*/
unsigned long expires = timer->expires;
unsigned long idx = expires - timer_jiffies;
if (idx < TVR_SIZE) {
int i = expires & TVR_MASK;
insert_timer(timer, tv1.vec, i);
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
int i = (expires >> TVR_BITS) & TVN_MASK;
insert_timer(timer, tv2.vec, i);
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
insert_timer(timer, tv3.vec, i);
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
insert_timer(timer, tv4.vec, i);
} else if (expires < timer_jiffies) {
/* can happen if you add a timer with expires == jiffies,
* or you set a timer to go off in the past
*/
insert_timer(timer, tv1.vec, tv1.index);
} else if (idx < 0xffffffffUL) {
int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
insert_timer(timer, tv5.vec, i);
} else {
/* Can only get here on architectures with 64-bit jiffies */
timer->next = timer->prev = timer;
}
}
在uClinux/linux/arch/m68knommu/platform/5272/config.c中的coldfire_timer_init中增加對TMR2初始化設置和中斷申請。然後自己寫TMR2的定時器中斷服務程序,
這個代碼可放在config.c中,也可加到OS代碼中:
uClinux/linux/arch/m68knommu/kernel/time.c:
這個文件中有LINUX使用TMR1的定時器中斷服務程序代碼:
void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
它是用來給LINUX OS提供時鐘的,自己的定時中斷就不必做這個工作了,讓它10ms進一次中斷,在自己的TMR2中斷程序中做自己的工作就可以了。當然這裏的處理一定要快。

19、關於C++支持
華恆HHCF系列開發套件光盤提供的軟件系統支持C++代碼,下面給出一個編譯參數的例子:
m68k-elf-g++ -m5307 -msep-data -Wl,-elf2flt -o test test.cpp -lstdc++ -lc -lgcc 
【注意】
這裏沒有加入庫的路徑和頭文件的路徑:-L和-I,請用戶在編譯時自己指定絕對路徑。
下面介紹一下將C++代碼統一到user目錄下像普通應用程序一樣參與編譯:
C++程序在5272上的編譯,首先要修改uclinux目錄下的config.arch文件,將其中的
CXX = $(CROSS_COMPILE)g++ 
改爲:
CXX = $(CROSS_COMPILE)g++ $(CPUFLAGS) -DCONFIG_COLDFIRE
再將其中的
CXXLIBS = $(LDPATH) $(LIBSTDCPP) $(LIBIOSTREAM) $(LIBIO) $(LIBIBERTY) \
$(LIBC) $(LIBGCC)
改爲:
CXXLIBS = $(LDPATH) $(LIBSTDCPP) $(LIBIBERTY) \
$(LIBC) $(LIBGCC)
然後模仿以下的Makefile書寫:
EXEC = test
OBJS = test.o
all: $(EXEC)
$(EXEC): $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(CXXLIBS)
romfs:
$(ROMFSINST) /bin/$(EXEC)
clean:
-rm -f $(EXEC) *.elf *.gdb *.o
即可。
說明:uclinux(uclibc)現在對iostream的支持還不夠,不能使用iostream庫。
【注】
華恆客戶可發信到[email protected]索取測試代碼。

20. 關於進程間通信IPC的問題
uClinux下system V的進程間通信IPC機制不可用!
(現在已經可以用了,在make menuconfig中內核配置菜單中選擇General setup --->,選中:
[*] System V IPC)
1、信號:但要求知道另一個進程的pid號:
進程間用信號通信時,用kill發送信號,但需要指定進程號,
可以這樣作:
接收信號的進程把自己的進程號寫到RAM盤(如/tmp目錄)下的一個文件中,發送信號的進程從這個文件中讀取這個進程號即可成功的實現信號發送。
這裏是直接指定內存地址(當然做好是在靠後的未用地址),然後用一個進程啓動另一個進程,這兩個進程之間的進程號恰好相差1,這樣就可以在兩個進程之間使用信號了。
2、共享文件:兩個進程訪問同一個文件,用文件鎖實現互斥訪問。
要保護/tmp/a文件,
在一個進程中每次要fopen前,先判斷是否有a.lock文件鎖,
若有就等待。
若沒有,則創建該文件鎖用open(O_CREAT|0_EXECL,
S_IRUSR|S_IWUSR)創建。
另一方法:在RAM中建立共享區(相當於文件)
在一個進程裏面分配一個內存快,然後將內存快的地址傳給
由vfork和exclp創建的另一個進程,這樣這兩個進程就可以對這塊內存進行讀寫了,對共享內存的互鎖是通過發信號實現的。
一共有4個進程,分別一個啓動一個,這樣他們的進稱號恰好是連續的,一就是說一個進程知道任意一個它想發信號的進程號。這樣就可以在所有進程間發信號了,共享內存是先分配內存塊,然後傳遞已經有操作系統分配好的共享內存地址,管道使用的pipe創建,然後使用vfork創建另一個進程,並傳遞管道的讀、寫fd,就可以讀寫管道了。
3、消息隊列
含消息隊列的程序編譯程序時會提示沒有定義符號--"msgctl,msgsnd,msgget,msgrcv";
在/uClinux/linux/ipc/msg.c裏有系統調用的源代碼
-"sys_msgget,sys_msgctl,sys_msgsnd,sys_msgrcv";
再查看系統uClinux\linux\arch\m68knommu\kernel/sys_m68k.c裏ipc系統調用裏調用--"sys_msgget,sys_msgctl,sys_msgsnd,sys_msgrcv"內核函數;
所以推斷是檔案libc.a裏沒包含"msgctl,msgsnd,msgget,msgrcv"原形函數調用;
做法:
1)make xconfig;選取SYSTEM V IPC
2)在/uClinux/lib/libc/生成目錄./msg
3)添加文件msgctl.c,msgsnd.c,msgget.c,msgrcv.c,寫相應的makefile;
4)修改上一級目錄裏makefile,添加msg目錄;->加函數到libc.a裏;
5)make dep;
6)make;
注意:在系統機上發消息隊列的長度和接收消息隊列的長度可以不等長;華恆內核中長度好象必須相等,(最大不要超過BUFSIZ=1024)。
消息隊列可以對其進行編址,使得各個進程各取所需,並且可以使消息隊列的個數變少。但是如果在消息隊列被刪除後還有N個要發送或檢索的進程,會發生問題 
信號量的做法一樣!

21、關於應用程序中使用GPIO的問題
關於GPIO,要設置三個寄存器,分別是:以PB口爲例
1)PBCNT,絕對各個引腳的複用信號是否爲IO
2)方向寄存器,每個引腳是輸入還是輸出。
3)數據寄存器,進行IO的輸入輸出。
給個例子代碼:(注意:這是在用戶應用程序中的代碼,不是內核態代碼)
*(volatile unsigned long *)0x10000080 &=0xff003fff; // PACNT 14-23 bit is cleared,use PA7-11
*((volatile unsigned short *)0x10000084 |= 0x0f80; // PADDR 7-11 bit is setted,use as output
*(volatile unsigned short *)0x10000086 = 0x0080; // PA7爲0,PA8爲0
*(volatile unsigned short *)0x10000086 = 0x0180; // PA7爲0,PA8爲1

22、關於管道的使用
下面是一個例子,在一個進程中通過管道啓動另一個進程test。
#include <sys/wait.h>
#include <stdio.h>
int main(void)
{
FILE *fd;
int waitstat;
char buf[20];
if((fd=popen("/bin/test","r"))==NULL)
printf("popen error! \n");
wait(&waitstat);
//pclose(fd);
if(fgets(buf,15,fd)==NULL)
printf("fgets error! \n");
printf("%s",buf);
return 0;
}
代碼移植到uC下時應在popen後加入,pclose(fd)或wait(&waitstat)。因爲uClibc中popen的實現與X86下的不同,它使用了vfork(PC上是用fork)必須等子進程可靠結束關閉文件後才執行對文件的下一步讀寫。

23. 關於ColdFire系列開發板的uClinux內核版本
華恆ColdFire系列開發板提供的嵌入式uClinux內核版本目前主要有兩種:2.0.38和2.4.x,
其中只有HHCF5272-R1還保留了2.0.38的內核版本,其它套件全部爲2.4內核。目前HHCF5272-R1也可以提供2.4的內核。
華恆版本的uClinux和從網上uClinux.org down下來的版本的區別在於:
1)網上開源的版本只提供了RAM版內核,不提供ROM版本,呵呵,這樣做我想可能就是爲了限制商業化用戶吧,因爲RAM版本還需要bootloader來引導(但行業內,bootloader基本上大家都不提供源代碼),不能直接啓動,根本無法作爲商業產品使用,因此也就只能給愛好者折騰着玩玩而已。華恆替客戶完成了這部分ROM化的工作。
2)華恆以本地化器件提供的硬件板卡,因此要針對自己的硬件修改系統啓動代碼、硬件設備驅動BSP,並相應的提供下載、燒寫等工具軟件,這些都要自己移植,修改或者完全自己定製。沒有這些輔助工具,空有uClinux的tar包,是根本無法進行開發調試的。
3)本地化全中文技術手冊及相關的技術支持(論壇)。

24. 關於不同內核版本間應用程序移植的問題
應用程序的移植一般的和內核版本是沒有任何關係的,當然有的應用程序是需要內核支持的,例如pppd等。在2.0.38內核和2.4內核之間互移應用程序,唯一要注意的就是Makefile的寫法:
其實區別就一句話,就是2.4下面,它把elf2flt作爲gcc的一個參數一步完成了,而2.0.38還要分爲兩步完成,體現在Makefile上就如下:
對於2.0.38:
$(LD) $(LDFLAGS) -o [email protected] $(OBJS) $(LDLIBS)
$(CONVERT)
對於2.4.x:
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

25、關於外設中斷的問題
MCF5272處理器提供了6路外部中斷以供外設控制芯片使用。在MCF5272的啓動代碼中(sysinit.c代碼中)屏蔽了所有的內部和外部中斷,因爲用戶在擴展使用自己的中斷源設備時,在該設備的驅動初始化代碼(如open函數中)中就必須手工打開允許這個外部中斷源。屏蔽和允許一箇中斷源都是通過設置ICRn寄存器來實現的。
在對應的PI位寫1,而後面的三位IPL位都爲0就表示屏蔽該中斷源。
在對應的PI位寫1,後面的三位IPL位寫001~111就表明打開運行該中斷源,並設置其中斷優先級爲1到7級,級別越高,優先級越高。
switch(irq)
{
case 1:
*(volatile unsigned long *)(0x10000020) |= 0xb0000000;
break;
case 3:
*(volatile unsigned long *)(0x10000020) |= 0x00b00000;
break;
case 4:
*(volatile unsigned long *)(0x10000020) |= 0x000b0000;
break;
case 5:
*(volatile unsigned long *)(0x1000002c) |= 0x0b000000;
break;
}

26、關於中斷的問題
在每個使用中斷的設備的驅動初始化代碼中,都首先要打開中斷,因爲啓動代碼把所有中斷都禁止(mask)了,根據CPU手冊,在ICRn對應的PI位寫1,而後面的三位IPL位都爲0就表示屏蔽該中斷源。即將對應ICR中對應的字節設置爲8。例如啓動時,ICR1就被設置爲:0x88888888。
打開中斷時,則在ICRn對應的PI位寫1,後面的三位IPL位寫001~111就表明打開運行該中斷源,並設置其中斷優先級爲1到7級,級別越高,優先級越高。例如MCF5272的幾個內部模塊所使用的內部中斷:
1)TIMER:在ICR1對應位設置0xd,即priority == 5(2.0.38用的是TMR1,2.4內核用的是TMR4)
2)FEC:在ICR3對應位設置0xd,即priority == 5
3)FEC要工作的同時還要使用MII(佔用INT2),在ICR1對應位設置0xd,即priority == 5
4)UART:在ICR2對應位設置0xe,即priority == 6
樣例代碼如下:
FEC:fec.c中int __init fec_enet_init(struct net_device *dev)
volatile unsigned long *icrp;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);//FEC
*icrp = 0x00000ddd;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);//MII
*icrp = (*icrp & 0x70777777) | 0x0d000000;
TMR4:在uClinux/linux-2.4.x/arch/m68knommu/platform/5272/config.c中對TIMER的初始化如下:
void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *))函數中有如下代碼:
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
*icrp = 0x0000000d; /* TMR4 with priority 5 */
request_irq(72, handler, SA_INTERRUPT, "ColdFire Timer", NULL); 
UART1/UART2:在uClinux/linux-2.4.x/drivers/char/mcfserial.c中,有如下代碼對UART進行中斷初始化:
static void mcfrs_irqinit(struct mcf_serial *info)
volatile unsigned long *icrp;
volatile unsigned long *portp;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
switch (info->line) {
case 0:
*icrp = 0xe0000000;
break;
case 1:
*icrp = 0x0e000000;
break;
此外,MCF5272相應外部中斷後,並不會自動的清楚該中斷的pending位,這樣用戶就必須在自己的中斷處理函數的末尾自己來替處理器完成這一工作。例如:對於外部中斷3
*(volatile unsigned long*)(MCF_MBAR+0x20) |= 0x00800000;

27、應用程序中如何定時產生信號?
這個問題就相當於實現WINDOWS下的WM_TIMER功能,定時給應用程序發送消息
例如:要求每一秒產生一個信號,去打印一句test。本來signal/alarm只能一次性工作,現在要讓它循環起來,每一秒都產生信號,就要再其信號處理函數中對其進行重置。
void test()
{
signal(SIGALRM,test);//重置
alarm(1);
printf("test\n");
}
main()
{
signal(SIGALRM,test);
alarm(1);
for(;;)
{/*主函數處理部分*/
}
}

28、應用程序的編譯參數觀察
用戶在編譯自己的應用程序時,也是要在uClinux下執行make,屏幕一滾就過去了,SHIFT+PAGEUP也翻不了那末多,其實自己的應用怎麼編譯的也不清楚。
在uClinux下執行make >&t,則自動生成臨時文件t,它記錄了整個編譯過程及每步編譯的詳細參數,對於理解編譯工具的使用及其參數非常有幫助。(整個的編譯過程詳細分析請參見手冊2.1.3節),舉例而言,以應用程序uClinux/user/inetd和ping爲例:
對於uClinux-2.0.38下的寫法如下:
/HHCF5272-R1/uClinux/tools/m68k-elf-gcc -m5200 -Wa,-m5200 -DCONFIG_COLDFIRE -Dl
inux -D__linux__ -Dunix -DEMBED -O2 -msoft-float 
-I/HHCF5272-R1/uClinux/tools/gcc-include -I/HHCF5272-R1/uClinux/lib/libc/include 
-I/HHCF5272-R1/uClinux/lib/libm 
-I/HHCF5272-R1/uClinux/vendors/include -fno-builtin -DSERVICES=\"/etc/services
\" -DINETD_CONF=\"/etc/inetd.conf\" -c -o inetd.o inetd.c
對於uClinux-2.4.17下的編譯全部以gcc爲前臺,連ld也被隱藏到後臺了:
m68k-elf-gcc -m5307 -DCONFIG_COLDFIRE -Os -g -fomit-frame-pointer -Dlinux 
-D__linux__ -Dunix -D__uClinux__ -DEMBED 
-I/HHCF5272-R1/uClinux/lib/libc/include -I/HHCF5272-R1/uClinux/lib/libm 
-I/HHCF5272-R1/uClinux -I/HHCF5272-R1/uClinux/linux-2.4.x/include 
-fno-builtin -msep-data -c -o ping.o ping.c
m68k-elf-gcc -m5307 -DCONFIG_COLDFIRE -Os -g -fomit-frame-pointer 
-Dlinux -D__linux__ -Dunix -D__uClinux__ -DEMBED 
-I/HHCF5272-R1/uClinux/lib/libc/include -I/HHCF5272-R1/uClinux/lib/libm 
-I/HHCF5272-R1/uClinux -I/HHCF5272-R1/uClinux/linux-2.4.x/include 
-fno-builtin -msep-data -Wl,-elf2flt -o ping ping.o 
-L/HHCF5272-R1/uClinux/lib/libc/. -L/HHCF5272-R1/uClinux/lib/libc/lib 
-L/HHCF5272-R1/uClinux/lib/libm -L/HHCF5272-R1/uClinux/lib/libnet 
-L/HHCF5272-R1/uClinux/lib/libdes -L/HHCF5272-R1/uClinux/lib/libpcap 
-L/HHCF5272-R1/uClinux/lib/libssl -lc
-L表明後面爲所要鏈接的libc庫的路徑。庫路徑可以有多個(對於一個應用程序而言,很多庫並沒有用),因此可以看到有多個-L參數;
-I參數表明後面所跟的爲C語言INCLUDE頭文件的路徑,這個路徑可以有多個,因此可以看到有多個-I參數;
-m5200(-m5307)爲處理器相關編譯參數,2.4下采用了-m5307,這其實對於應用程序而言沒有任何區別;
-c後面爲所要編譯的C文件;
-o後面爲這行編譯操作的目的,即這行編譯完畢後要生成的文件;
-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce:這些都是編譯參數;

29、FLASH上數據保存 
鑑於目前發行的開發板中的uClinux均採用ROMFS作爲其根文件系統,因此其目錄大多是不可寫的。只有/var,/tmp是RAM盤可寫,但板子一掉電裏面的內容就丟失了,因此只能作臨時文件保存,無法永久的保存數據,例如配置文件等。下面大概介紹一下幾種FLASH上保存配置的方法:
1、對於簡單的數據,小的配置文件等,而且不是非常頻繁的(例如一分鐘寫10次)寫入的,可以直接自己在FLASH的空餘處(例如第二片FLASH上)劃出一塊區域,以自己定義的方式寫入,並在板子啓動時自動讀出。華恆提供了這樣的樣例代碼,即user/memtools/,其詳細介紹在手冊第二章“FLASH扇區保存IP地址”一節。這樣作最大的好處是用戶的控制程度最大,形式最靈活,保存的可以是自定義的數據,可以不是文件的形式。而下面的幾種方式都是要求文件的形式保存,無法處理自定義的數據保存。
2、對於比較多的配置文件,一般的都先寫在RAM盤中,然後選擇保存,一次性寫入FLASH的某幾個扇區。這時就可使用flatfsd軟件,它的使用需要內核的配合支持,即要在blkmem.c中爲其指定保存數據的幾個扇區的起始/結束地址。這中方式也不能適應非常頻繁的寫入。
使用說明:將要保存的文件放在板子的RAM盤目錄/etc/config目錄下,因爲uClinux的根目錄/是建於FLASH上的romfs文件系統,是不可寫的,只有幾個RAM盤纔可寫,可用mount命令查看:
/etc> mount
rootfs on / type rootfs (rw)
/dev/rom0 on / type romfs (ro)
/proc on /proc type proc (rw)
/dev/ram0 on /var type ext2 (rw)
/dev/ram1 on /etc/config type ext2 (rw)
/dev/mtdblock0 on /sbin type jffs2 (rw)
要保存的時候,就在minicom裏面執行
killall -10 flatfsd
或者在C程序代碼裏面用vfork+execlp執行這句命令行即可.
這樣就會自動將RAM盤中/etc/config目錄裏面的文件全部保存寫入到板子FLASH的扇區裏面(具體哪幾個扇區是由linux-2.4.x/drivers/block/blkmem.c中指定的,可在板子啓動信息裏面看到:)
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 2 disk images:
0: FFC77362-FFCCE761 [VIRTUAL FFC77362-FFCCE761] (RO) /*romfs*/
1: FFFC0000-FFFFFFFF [VIRTUAL FFFC0000-FFFFFFFF] (RW) /*flatfsd*/
能夠保存的機制是由如下文件的一行保證的:
/etc> cat inittab
inet:unknown:/bin/inetd
flt:unknown:/bin/flatfsd 
這樣就保證系統啓動後系統進程裏面有flatfsd進程永遠在運行,才能保證接收兵處理用戶發來的數值爲10的信號SIGNAL:
/etc> ps
PID PORT STAT SIZE SHARED %CPU COMMAND
1 S 37K 0K 0.0 init
2 S 0K 0K 0.0 keventd
3 R 0K 0K 0.2 ksoftirqd_CPU0
4 R 0K 0K 22.7 kswapd
5 S 0K 0K 0.0 bdflush
6 S 0K 0K 0.0 kupdated
7 S 0K 0K 0.0 mtdblockd
16 S 0K 0K 0.0 jffs2_gcd_mtd0
30 S0 S 85K 0K 0.0 /bin/sh
31 S 38K 0K 0.0 /bin/inetd
32 S 53K 0K 0.0 /bin/flatfsd
33 S 190K 0K 2.2 /bin/diald -f /etc/config/diald.pppoe1
34 S 207K 0K 0.0 /bin/dhcpd -d -cf /etc/config/dhcpd.conf eth0
1220 S 149K 0K 0.0 /bin/pppd -detach mtu 1454 mru 1454 file /etc/config/pppoe1
1221 S 69K 0K 7.4 /bin/pppoe -I eth0 -T 3000 -m 1412 -p /var/log/pppoe.pid
1241 S 49K 0K 0.0 /bin/telnetd
1242 p2 R 88K 0K 0.0 sh 
而板子啓動時通過執行/etc/rc裏面的flatfsd –r就可以將FLASH上的保存的文件恢復到RAM盤目錄/etc/config/下。
/> cd /etc/
/etc> cat rc
hostname mp3server
/bin/expand /etc/ramfs.img /dev/ram0
/bin/expand /etc/ramfs.img /dev/ram1
mount -t proc proc /proc
mount -t ext2 /dev/ram0 /var
mount -t ext2 /dev/ram1 /etc/config
mount -t jffs2 /dev/mtdblock0 /sbin
mkdir /var/tmp
mkdir /var/log
mkdir /var/run
mkdir /var/lock
/bin/flatfsd -r
touch /etc/config/dhcpd.leases
ifconfig lo 127.0.0.1
ifconfig eth0 192.168.2.254 netmask 255.255.255.0
ifconfig eth0:1 192.168.1.2 netmask 255.255.255.0
/bin/ena -e
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
注意:若想修改板子啓動後/etc/config裏面的文件的內容,例如 板子啓動後的IP地址設置文件/etc/config/start文件,需要如下操作:
修改uClinux源代碼uClinux-dist/romfs/etc/default/start文件內容,然後重新編譯生成image.bin,燒寫板子,板子啓動後,在minicom裏面執行
cp /etc/default/start /etc/config
killall -10 flatfsd
這樣下次啓動就會自動生效。
3、對於比較頻繁的數據保存,就要在板子上建立額外的日誌型文件系統JFFS/JFFS2,或者乾脆就用JFFS/JFFS2取代ROMFS作根文件系統。這樣板子的目錄就是可寫的,就像硬盤一樣,不需要額外的工具來負責將數據寫入FLASH。JFFS爲2.0.38內核所支持,它不支持JFFS2,JFFS2到2.4內核才被支持,它採用了成熟穩定的MTD技術,因此要比JFFS穩定。這兩種文件系統要在uClinux上實現支持並不複雜,但它的實用還需要一些額外的工作,例如燒寫工具的配合,新型image.bin編譯生成,因爲真正產品化的軟件是不能允許每次啓動後都還要進行許多的手工操作,例如加載文件系統等,板子出廠燒寫也要一次完成,而不能還要分多次燒寫等等,這些工作都是比較繁雜的,而且沒有燒寫工具的源代碼是無法完成的。華恆提供JFFS/JFFS2整套軟件技術。

30、關於2.4內核版本下的RAM版內核的編譯 
對於2.0.38內核,華恆提供了完備的ram.ld和crt0_ram.S,它們和華恆提供的bootloader可配合使用。 對於2.4.17的內核,從網上直接DOWN的uClinux-Coldfire版本(例如最新版本:uClinux-dist-20020701.tar.gz)是可以直接在華恆bootloader提示符HHCN>下執行readàgo 100000跑起來的。而若客戶要從華恆2.4系列開發套件軟件系統的基礎上改動跑RAM版則需要做一些改動纔可以的,例如HHCF5272-LCD-IDE-R1、HHCF5272-2ETH-R2等都是採用的2.4內核。因爲華恆板子燒在FLASH上的就是一個RAM版本的內核,經由華恆的bootloader解壓複製到RAM中才激活執行的,它的執行方式和readàgo的方式是完全不同的,雖然都是RAM版。要做到這一點,華恆是做了一些改動的,而現在實際上就是要恢復成從網上直接DOWN下來的狀態。
1、首先是crt0_ram.S和直接下載的uClinux-Coldfire版本的crt0_ram.S有區別,是經過華恆修改的代碼,若直接使用必然無法通過bootloaderàreadàgo 100000而跑起來。因此這時就必須使用網上下載的原始未經改動的crt0_ram.S,其實兩個文件的區別很小,僅在於華恆的版本註釋了複製romfs的部分代碼:
只要把uClinux/linux-2.4.x/arch/m68knommu/platform/5272/HHTECH/crt0_ram.S中的一個#if 0 改爲#if 1
下面貼出華恆代碼:
_start:
nop /* Filler */
move.w #0x2700, %sr /* No interrupts */
/*
* Setup VBR here, otherwise buserror remap will not work.
* if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
*
* [email protected] 19990306
*
* Note: this is because dBUG points VBR to ROM, making vectors read
* only, so the bus trap can't be changed. (RS)
*/
move.l #VBR_BASE, %a7 /* Note VBR can't be read */
movec %a7, %VBR
move.l %a7, _ramvec /* Set up vector addr */
move.l %a7, _rambase /* Set up base RAM addr */
/*
* Set to 4 meg for the Cadre III board (m5206e).
*/
move.l #MEM_SIZE, %a0
move.l %a0, %d0 /* Mem end addr is in a0 */
move.l %d0, %sp /* Set up initial stack ptr */
move.l %d0, _ramend /* Set end ram addr */
#if 1
/*
* Enable CPU internal cache.
*/
move.l #0x01000000, %d0 /* Invalidate cache cmd */
movec %d0, %CACR /* Invalidate cache */
move.l #0x80000100, %d0 /* Setup cache mask */
movec %d0, %CACR /* Enable cache */
#endif
/*
* Move ROM filesystem above bss :-)
*/
lea.l _ebss, %a1 /* Set up destination */
move.l %a1, _ramstart /* Set start of ram */
#if 1【這裏原來是#if 0,即在華恆版本中被註釋掉了】
lea.l _sbss, %a0 /* Get start of bss */
lea.l _ebss, %a1 /* Set up destination */
move.l %a0, %a2 /* Copy of bss start */
move.l 8(%a0), %d0 /* Get size of ROMFS */
addq.l #8, %d0 /* Allow for rounding */
and.l #0xfffffffc, %d0 /* Whole words */
add.l %d0, %a0 /* Copy from end */
add.l %d0, %a1 /* Copy from end */
move.l %a1, _ramstart /* Set start of ram */
_copy_romfs:
move.l -(%a0), %d0 /* Copy dword */
move.l %d0, -(%a1)
cmp.l %a0, %a2 /* Check if at end */
bne _copy_romfs
#endif
/*
* Zero out the bss region.
*/
lea.l _sbss, %a0 /* Get start of bss */
lea.l _ebss, %a1 /* Get end of bss */
clr.l %d0 /* Set value */
_clear_bss:
move.l %d0, (%a0)+ /* Clear each word */
cmp.l %a0, %a1 /* Check if at end */
bne _clear_bss
/*
* load the current task pointer and stack
*/
lea init_task_union, %a0
movel %a0, _current_task
lea 0x2000(%a0), %sp
/*
* Assember start up done, start code proper.
*/
jsr start_kernel /* Start Linux kernel */
_exit:
jmp _exit /* Should never get here */
2、ram.ld也要有修改,
MEMORY {
ram : ORIGIN = 0x100000, LENGTH = 0x6e0000
}
從網上直接DOWN下來默認的ORIGIN = 0x20000,這樣用我們的bootloader下載下去當然是跑不起來的。以下的SECTIONS 節不需要任何改動。
3、修改vendors/HHTECH/M5272/Makefile
image:
[ -d $(IMAGEDIR) ] || mkdir -p $(IMAGEDIR)
/usr/local/bin/genromfs -v -V "ROMdisk" -f $(ROMFSIMG) -d $(ROMFSDIR)
m68k-elf-objcopy -O binary $(ROOTDIR)/$(LINUXDIR)/linux \
$(IMAGEDIR)/linux.bin
#gzip -f $(IMAGEDIR)/linux.bin 【註釋掉】
#cat $(IMAGEDIR)/linux.bin.gz $(ROMFSIMG) > $(IMAGE) 【註釋掉】
cat $(IMAGEDIR)/linux.bin $(ROMFSIMG) > $(IMAGE)
$(ROOTDIR)/tools/cksum -b -o 2 $(IMAGE) >> $(IMAGE)
[ -n "$(NO_BUILD_INTO_TFTPBOOT)" ] || cp $(IMAGE) /tftpboot
#$(MAKE) -C ../../../colilo 【註釋掉】
BSS=`m68k-elf-objdump --headers $(ROOTDIR)/$(LINUXDIR)/linux | \
grep .bss` ; \
ADDR=`set -- $${BSS} ; echo 0x$${4}` ; \
m68k-elf-objcopy --add-section=.romfs=$(ROMFSIMG) \
--adjust-section-vma=.romfs=$${ADDR} --no-adjust-warnings \
--set-section-flags=.romfs=alloc,load,data \
$(ROOTDIR)/$(LINUXDIR)/linux $(ELFIMAGE) 2> /dev/null
4、修改linux-2.4.x/drivers/block/blkmem.c的第125行開始的幾句,註釋掉defined(CONFIG_HHTECH),修改後代碼如下:
#ifdef CONFIG_COLDFIRE
#ifdef CONFIG_TELOS
#undef CONFIG_CARDE3
#define CAT_ROMARRAY
......
其實關鍵就是去掉CAT_ROMARRAY的定義。

31、2.4 Linux內核大小 
uClinux/linux-2.4.x/目錄下編譯出來的linux文件有5M多,這是ELF格式的文件,它轉換成image.bin時還要用m68k-elf-objcopy工具轉換成binary格式的linux.bin,這時它就只有800k了,再壓縮一下就變成300k了。這個工作具體可參見uClinux/vendors/HHTECH/M5272/Makefile。

32、從SDRAM中劃出一塊不讓Linux訪問,供自己使用,可作共享內存用
對於2.4內核修改uClinux/linux-2.4.x/arch/m68knommu/platform/5272/HHTECH/crt0_ram.S(對於2.0ROM版,爲uClinux/linux/arch/m68knommu/platform/5272/MOTOROLA/crt0_rom.S),只要修改一處:即文件最前面定義的MEM_SIZE宏,華恆提供的爲0x01000000,即16M。用戶若想劃出8M爲自己管理使用,只要將這個值改爲0x00800000即可。這樣作就是不讓LINUX知道還有這8M地址,這樣OS在分配內存的時候就不會用到這些地址空間,相當於從OS那裏偷內存給自己使用。例如可用於內核驅動和應用程序的通信用共享內存等。

33、關於通過NFS mount宿主機硬盤調試應用程序的問題
嵌入式LINUX調試應用程序最主要的方式就是通過NFS mount宿主機硬盤上的應用程序來執行,通過觀察其在串口終端打印的信息來達到調試的目的。
在這個過程中,存在一個權限的問題,即板子mount宿主機硬盤後,這個NFS mount的操作默認的不是以root的權限執行的,因此一般的板子沒有權限執行宿主機硬盤上的程序,這時就要在宿主機上執行chmod 777 app,其中app爲應用程序可執行文件的名字。其實這種現象還是比較容易爲開發人員解決的,因爲當執行應用時,minicom就會報錯,permision denied,或者unknown error 4。但對於有的情況就不一定這麼容易看出是權限的問題:
例如:調試WEB管理軟件cgi代碼時,我們把宿主機上/cgi-bin/通過NFS mount到板子的CGI工作目錄/home/httpd/cgi-bin/上,這時通過瀏覽器IE執行CGI操作時,就會報錯403,這裏也是一個權限的問題,即CGI要求其工作目錄可寫,這時就必須在宿主機上執行:chmod 777 /cgi-bin,這時瀏覽器裏立刻就可以工作了。

34、關於uClinux下線程的使用
使用線程是要求uClibc里加入pThread庫編譯。
這樣就要求make menuconfig時選擇uClibc,而不是華恆默認選擇的uC-libc。
在uClibc中選擇pThread庫,可以按照以下操作:
1.cd uClibc
2.make menuconfig CROSS=m68k-elf-
3.選上posix thread support選項
4.cd ..
5.make clean
6.make
庫選擇好之後,先不必自己編制應用程序,uClinux提供了完備的測試程序:即uClinux/user/threaddemos
你make menuconfig在應用程序中選擇這個程序加入編譯,看是否可以編譯通過,通過後執行是否正確即可。
若編譯有錯誤,可以直接到user/threaddemos目錄下,執行:
m68k-elf-gcc -m5307 -msep-data -Wl,-elf2flt -o bcdm bcdm.c -lpthread -lc
可直接生成可執行文件bcdm,可直接mount到板子上執行。
【注意】
這裏要求使用20030314的elf-tools 。
華恆客戶可發信到[email protected]索取相關測試代碼。

35、關於支持模塊動態加載(Loadable Module)的問題
在make menuconfig中配置內核時選擇:Loadable module support --->
[*] Enable loadable module support 
[] Set version information on all module symbols (NEW)
[*] Kernel module loader (NEW)
並在應用程序配置中選擇busybox下的insmod/rmmod/lsmod,
並選中: [*] Post 2.1 kernel modules。
關於驅動模塊的.c(例如mydriver.c)可這樣編譯,不需要單獨寫Makefile,就直接放到uClinux/linux2.4.x裏面參與內核編譯即可:
cp mydriver.c uClinux-dist/linux-2.4.x/drivers/char
然後修改uClinux-dist/linux-2.4.x/drivers/char/Makefile,
obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o mydriver.o
在最後加入mydriver.o
這樣內核就會用正確的參數編譯出mydriver.o。
然後把這個mydriver.o單獨複製出來到uClinux-dist/romfs/usr下面,然後再把uClinux-dist/linux-2.4.x/drivers/char/Makefile恢復回去,然後再重編內核,燒寫,啓動後執行insmod /usr/mydriver.o即可成功。再lsmod看看。

36、關於支持應用程序動態鏈接uClibc的問題
早期的uClinux下的應用程序都是採用靜態鏈接的方式鏈接uClibc/uC-libc,現在uClinux早就已經可以支持動態鏈接uClibc庫了。動態鏈接的好處是可以實現多個應用程序實現代碼共享,從而可以節省內存消耗,就相當於WINDOWS下的DLL所引入的共享優勢。
動態鏈接在NOMMU處理器上的實現採用了XIP(execute in place)代碼。
詳細分析參見:
http://mailman.uclinux.org/pipermail/uclinux-dev/2002-April/007786.html

37、關於最新的20030314 elf toolschain
參見:http://www.uclinux.org/pub/uClinux/m68k-elf-tools/
下載m68k-elf-tools-20030314.sh到LINUX PC機上,chmod 777 m68k-elf-tools-20030314.sh,然後./m68k-elf-tools-20030314.sh則直接將最新的m68k-elf-xxx工具集合安裝到/usr/local/下面,可以直接使用。

38、執行我的應用程序時報錯:BINFMT_FLAT: bad magic/rev (0x1010100, need 0x4)
例如:mount宿主機上的nmbd,在minicom下執行/mnt/nmbd&,出現如下錯誤:
BINFMT_FLAT: bad magic/rev (0x1010100, need 0x4)
BINFMT_FLAT: bad magic/rev (0x1010100, need 0x4)
/mnt/nmbd: Exec format error
這是因爲這個應用程序沒有使用交叉編譯工具編譯,而是用了PC Linux下的gcc編譯出來的。造成這種問題的經常是由於客戶不是在uClinux目錄下執行make統一進行編譯,而是直接到該應用程序目錄下執行make所致。這是由於uClinux/user/下每個應用程序的Makefile中使用了許多宏,列入CC等,這些宏都是統一在uClinux下的一個目錄下的文件中定義的,若用戶直接到user/下的應用程序目錄下執行make,則這些宏就無法獲取uClinux爲其設定的值,而是自動採用PC Linux系統默認的,例如CC若用戶不指定,默認的就是gcc,所以應用程序就沒有用m68k-elf-gcc編譯,而是用PC Linux下的gcc編譯的,這樣編出來的可執行文件在板子上當然是無法執行的了。

39、關於關閉shell,使能串口通信
鑑於我們提供的版本不斷的升級,所以針對不同版本的方法略有區別,下面一共提供兩種方法:
方法一
1.修改uClinux/linux-2.4.x/init/main.c
- if (open("/dev/ttyS0", O_RDWR, 0) < 0)
+ if (open("/dev/null", O_RDWR, 0) < 0)
修改以後啓動過程中printk內容仍會打印,printf內容如rc內步驟不會打印。
2.同時最好在user/init/simpleinit.c中不要啓動/bin/sh,具體操作是:
/* Fake an inittab entry if boot console defined */
#ifdef CONFIG_USER_INIT_CONSOLE_SH
#if LINUX_VERSION_CODE < 0x020100
if (console_device && strcmp(console_device, "/dev/null"))
#else
if (have_console)
#endif
/*{ 【就是註釋掉這一段代碼!!!!】
struct initline *p;
p = inittab + numcmd++;
init_itab(p);
strcpy(p->fullline, "console");
strcpy(p->tty, "console");
strcpy(p->termcap, "linux");
p->toks[0] = "/bin/sh";
} */
#endif
**************************************************************************************
方法二
【這是最新的測試結果】
通常不能使用COM1進行串口通信的原因是它已被重定向爲標準輸入輸出,系統的shell進程將對其監視並處理從此處發送進來的數據,而不能被用戶程序所得到。
解決辦法我認爲有兩種,一是不把Com1口重定向爲標準輸入輸出,二是在標準輸入輸出上不啓動shell。第一種沒有試過,第二種可以按下面方法修改。
ü uC的版本很多,好像有一種是在uClinux/linux-2.4.x/init/main.c中啓動shell,該代碼在do_shell函數中,檢查main.c文件,如果有該函數,把
if(open("/dev/ttyS0",O_RDWR,0)<0)
改爲
if(open("/dev/null",O_RDWR,0)<0)
沒有就算了。
在uClinux/user/init/simpleinit.c中注掉read_inittab函數中下面HHTECH部分的內容:
void read_inittab(void)
{
numcmd = 0;
/* Fake an inittab entry if boot console defined */
#ifdef CONFIG_USER_INIT_CONSOLE_SH
#if LINUX_VERSION_CODE < 0x020100
if (console_device && strcmp(console_device, "/dev/null"))
#else
if (have_console)
#endif
/*HHTECH
{
struct initline *p;
p = inittab + numcmd++;
init_itab(p);
strcpy(p->fullline, "console");
strcpy(p->tty, "console");
strcpy(p->termcap, "linux");
strcpy(p->termcap, "linux");
p->toks[0] = "/bin/sh";
}
*/
#endif
read_initfile(_PATH_INITTAB);
#ifdef CONFIG_USER_FLATFSD_FLATFSD
read_initfile(_PATH_CONFIGTAB);
#endif
if (numcmd == 0)
_exit(1);
}
注意:
這樣並不是說就永遠不會啓動shell了,只是在標準輸出上不啓動shell,但若用戶telnet板子還是仍然會在p0口上啓動shell的,否則用戶就永遠無法向板子發佈command命令了。
方法三
make menuconfig
Kernel hacking --->
[*] Compiled-in Kernel Boot Parameter
Kernel Boot Parameter: "CONSOLE=/dev/null" 
這樣選擇最徹底,minicom裏面沒有任何內核啓動的信息,但可以telnet板子操作。

40、關於malloc使用問題
在HHCF5272-R2的uClinux下測試, malloc最大空間約爲2,048,000
設爲2,100,000時,出現:
kernel panic : BUG!
另:realloc結果同malloc一樣,大小上沒有區別;在內核中使用kmalloc,大小亦相同。

41、MFC5272-16com 開發板串口波特率設置?
#define SETBAUDRATE 0xe021
#define SETBUFFER 0xe022
#define SETFORMAT 0xe023
對串口波特率修改爲
ioctl(spfd,SETBAUDRATE,4);
波特率表
char hh_mcf5272_baud_table[10][2] = {
{ 0x80, 0x01 }, /* 1200 300 *///0
{ 0xc0, 0x00 }, /* 2400 600 *///1
{ 0x60, 0x00 }, /* 4800 1200 *///2
{ 0x30, 0x00 }, /* 9600 2400 *///3
{ 0x18, 0x00 }, /* 19.2K 4800 *///4
{ 0x0c, 0x00 }, /* 38.4K 9600 *///5
{ 0x06, 0x00 }, /* 76.8K 19K *///6
{ 0x03, 0x00 }, /* 153.6K 38k *///7
{ 0x02, 0x00 }, /* 230.4K 56k *///8
{ 0x01, 0x00 } /* 460.8K 115k *///9
};
4就對應上表的19200,默認串口波特率爲19200
對串口傳輸格式修改
ioctl(spfd,SETFORMAT,"8n1");
默認爲8n1

42、關於CGI
CGI是一種WEB SERVER端擴展代碼。例如IIS端的ISAPI等開發的DLL代碼都是WINDOWS上的WEB SERVER端的擴展,用於處理用戶通過WEB瀏覽器的表單輸入等靜態頁面以外的智能輸入處理。
CGI可用於WINDOWS和LINUX上的WEB SERVER端擴展,可用各種腳本如PHP等實現,最原始的就是用C代碼實現的,具體用什麼代碼要看你的WEB SERVER是否支持。對於嵌入式LINUX採用的boa這個WEB SERVER而言,就不支持任何的腳本,只支持C代碼的CGI程序,每連接一個客戶端瀏覽器連接就在SERVER端(板子上)啓動一個CGI進程的COPY。

43、在REDHAT 9.0環境下使用BDM時,提示“DEVICE BUSY”,是並口被佔用?
請在您的REDHAT9機器上執行如下命令
rmmod lp
rmmod parport_pc
rmmod parport
這時您再執行./chk就沒有問題了。

44、xxx函數或者結構體是在哪裏定義的等類似的問題。
在LINUX這種開源的環境下工作,最重要的不是你己經掌握了多少知識,而是要掌握獲取信息的手段,源代碼都有,所有的知識都在那個uClinux的目錄下,不需要任何的書籍,只有有搜索和查找的工具就可以獲取任何需要的知識,搞開發就像學語言,模仿是非常有效的手段,看系統中運行的代碼是怎麼寫的,仿照着做就是了。
搜索和查找的手段就兩個:
一個是在所有文件中搜索字符串:
grep xxx * -r
另一個是搜索文件:
find -name xxx.c
還有,可在uClinux目錄下(其實任何目錄都可以,只是作用範圍小些)用:
ctags -R .
這樣在vi中閱讀代碼時可用ctrl+]跳轉到想要查詢的函數/結構定義處;用ctrl+T返回。

45、關於uClinux浮點支持
1.從/uClinux/lib/libm複製gcvt.c和mathf.h到/uClinux/lib/libc/stdio2
2.修改/uClinux/lib/libc/stidio2/Makefile
2a.增加gcvt.o編譯項到
OBJ= $(AOBJ) $(POBJ) $(SOBJ) dputs.o snprintf.o getdelim.o getline.o 
gcvt.o
~~~~~~添加項
2b.添加編譯參數-DFLOATS=1到all: $(LIBC) $(OBJ)前面
3.可增加make clean相關項
Makefile文件如下:
# Copyright (C) 1995,1996 Robert de Bath 
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
LIBC=../libc.a
ASRC=stdio.c
AOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o \
puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o \
setbuffer.o setvbuf.o ungetc.o
PSRC=printf.c
POBJ=printf.o sprintf.o fprintf.o snprintf.o vprintf.o vsprintf.o \
vfprintf.o vfnprintf.o vsnprintf.o
SSRC=scanf.c 
SOBJ=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o
OBJ= $(AOBJ) $(POBJ) $(SOBJ) dputs.o getdelim.o getline.o gcvt.o
CFLAGS += -DFLOATS=1
all: $(LIBC) $(OBJ)
#@$(RM) $(OBJ)
$(LIBC): $(LIBC)($(OBJ))
$(LIBC)($(AOBJ)): $(ASRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(AR) $(ARFLAGS) $@ $*.o
$(LIBC)($(POBJ)): $(PSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(AR) $(ARFLAGS) $@ $*.o
$(LIBC)($(SOBJ)): $(SSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(AR) $(ARFLAGS) $@ $*.o
transfer:
-@rm -f ../include/stdio.h
cp -p stdio.h ../include/.
clean:
rm -f *.o libc.a
$(LIBC)($(OBJ)): stdio.h 

46、關於用vfork實現多進程
N多客戶不停的在問vfork是否真正的多進程,要不就是認爲父進程被掛起了。
這裏給個明確的答覆,vfork+exec是多進程,而且父子進程同時並行執行,下面是個標準的例子代碼:
if ((pid=vfork())<0){
;
}
else if (pid==0){//child
//execl("/bin/sh","/bin/sh","/tmp/tmp1",0);
execl("/bin/sh","/bin/sh","/tmp/tmp1",(char*)0);
exit(0);
}

47、在RH7.2上無法make的問題
1.uClinux-dist/linux-2.4.x/scripts
mv mkdep mkdep.bak
gcc -o mkdep mkdep.c
mv split-include split-include.bak
gcc -o split-include split-include.c
2.uClinux-dist/config/scripts
download lxdialog-OK-rh7.2.tgz from HHTech to / 
cd uClinux-dist/config/scripts
mv lxdialog lxdialog.bak
tar xzf /lxdialog-OK-rh7.2.tgz
cp lxdialog/lxdialog /
cd uClinux-dist/linux-2.4.x/scripts/lxdialog
mv lxdialog lxdialog.bak
cp /lxdialog .
then 
make dep
make menuconfig
works fine!!
Happy hacking:-(.
注意:上面的lxdialog-OK-rh7.2.tgz在華恆目前提供的軟件光盤上都有提供。

48、關於uClinux下執行make menuconfig的說明
一般的,在LINUX下執行make menuconfig只是對LINUX內核進行配置。但uClinux將linux-2.4.x內核和應用程序user都整合到uClinux目錄下,並將對應用程序的選擇也集成到make menuconfig裏面,下面給出簡單的使用說明:
在字符界面下,不要進入XWindows,
cd uClinux-dist
make menuconfig
出現對話框,內容如下:(注意:下面有許多│ │,這是因爲終端軟件貼圖的緣故)
Target Platform Selection ---> │ │
│ │ --- │ │
│ │ Load an Alternate Configuration File │ │
│ │ Save Configuration to an Alternate File │ │

選擇Target Platform Selection --->回車,出現如下界面:
--- Choose a Vendor/Product combination. │ │
│ │ (HHtech/M5249) Vendor/Product │ │
│ │ --- Kernel is linux-2.4.x │ │
│ │ (uC-libc) Libc Version │ │
│ │ [ ] Default all settings (lose changes) │ │
│ │ [*] Customize Kernel Settings │ │
│ │ [*] Customize Vendor/User Settings (NEW) │ │
│ │ [*] Update Default Vendor Settings 
選擇(即 [*] )第二項:[*] Customize Kernel Settings就是要對內核進行裁減配置;選擇第三項:[*] Customize Vendor/User Settings (NEW)就是要挑選應用程序,至於第四項可選可不選,選了是當你的這個uClinux版本作爲發佈版本時,用戶選擇Default all settings (lose changes)就完全使用你的出廠配置。當然這個對於普通用戶而言是沒有什麼用的。
選擇完畢後,選擇下面的< Exit > 逐層退出,最後按照提示保存配置,則會分別出現內核和應用程序的選配菜單:
下面是內核配置菜單:
Linux Kernel v2.4.20-uc0 Configuration
Code maturity level options ---> │ │
│ │ Loadable module support ---> │ │
│ │ Processor type and features ---> │ │
│ │ General setup ---> │ │
│ │ Memory Technology Devices (MTD) ---> │ │
│ │ Parallel port support ---> │ │
│ │ Plug and Play configuration ---> │ │
│ │ Block devices ---> │ │
│ │ Networking options ---> │ │
│ │ Telephony Support ---> │ │
│ │ ATA/IDE/MFM/RLL support ---> │ │
│ │ SCSI support ---> │ │
│ │ I2O device support ---> │ │
│ │ Network device support ---> │ │
│ │ Amateur Radio support ---> │ │
│ │ IrDA (infrared) support ---> │ │
│ │ ISDN subsystem ---> │ │
│ │ Old CD-ROM drivers (not SCSI, not IDE) ---> │ │
│ │ Character devices ---> │ │
│ │ File systems --->
......
隨便選擇一項,回車即可進去配置。配置完內核後保存配置,< Exit >退出則進入應用程序選配菜單:
下面是應用程序配置菜單:
uClinux v1.3.4 Configuration
Core Applications ---> │ │
│ │ Library Configuration ---> │ │
│ │ Flash Tools ---> │ │
│ │ Filesystem Applications ---> │ │
│ │ Network Applications ---> │ │
│ │ Miscellaneous Applications ---> │ │
│ │ BusyBox ---> │ │
│ │ Tinylogin ---> │ │
│ │ MicroWindows ---> │ │
│ │ Games ---> │ │
│ │ Miscellaneous Configuration ---> │ │
│ │ Debug Builds ---> │ │
│ │ --- │ │
│ │ Load an Alternate Configuration File │ │
│ │ Save Configuration to an Alternate File 
選擇其中一項即可進行選擇,例如:要加入一些網絡類程序,例如DHCP服務器/客戶端,SNMP,pppd/pppoe等都是選擇Network Applications --->,回車後進入如下界面:打上*號即表示選中。
[ ] arp │ │
│ │ [*] boa │ │
│ │ [ ] boa uses SSL (NEW) │ │
│ │ [ ] bpalogin │ │
│ │ [ ] br2684ctl │ │
│ │ [ ] brcfg │ │
│ │ [ ] bridge utils │ │
│ │ [ ] dhcpcd │ │
│ │ [ ] dhcpcd-new (2.0/2.4) │ │
│ │ [ ] dhcpd │ │
│ │ [ ] dhcpd(ISC) │ │
│ │ [ ] dhclient(ISC) │ │
│ │ [ ] dhcrelay (ISC) │ │
│ │ [ ] diald │ │
│ │ [*] discard │ │
│ │ [ ] dnsmasq │ │
│ │ [ ] ethattach │ │
│ │ [ ] ez-ipupdate │ │
│ │ [*] ftp │ │
│ │ [ ] ftpd 
還有常用的就是busybox的選配:
BusyBox --->
[*] BusyBox │ │
│ │ --- Applets │ │
│ │ [ ] adjtimex │ │
│ │ [ ] ar │ │
│ │ [ ] basename │ │
│ │ [*] cat │ │
│ │ [ ] chgrp │ │
│ │ [ ] chmod │ │
│ │ [ ] chown │ │
│ │ [*] chroot │ │
│ │ [ ] clear │ │
│ │ [*] cmp │ │
│ │ [ ] cp │ │
│ │ [*] cut │ │
│ │ [*] date │ │
│ │ [ ] dc │ │
│ │ [ ] dd │ │
│ │ [*] df │ │
│ │ [ ] dirname │ │
│ │ [ ] dmesg 
......
還有就是編譯自己在uClinux/user下添加的應用程序時,一定要返回在uClinux目錄下執行make
不能直接在這個應用程序目錄下執行make,這樣做也不會慢的,因爲內核和uC-libc庫及其它user下的應用程序都已經編譯過了,編譯過程只是簡單的檢查一下STAMP,看它們都已經編譯過了,就不再理睬,而直接找到你剛改動的應用程序目錄進行編譯,比單獨編譯這個應用程序慢一點點而已。
對於armlinux和ppclinux而言,則應用程序就要逐個單獨編譯了,有人覺得這樣方便,但也有人喜歡前者,呵呵,蘿蔔青菜各有所愛:-)

49、關於uClibc和pThread庫的一個BUG(感謝杭州客戶李淵先生提供資料) 
uCLibc/libc/stdlib/malloc/free.c裏面有個小錯誤,這個錯誤只有在大程序,大數據並且使用了pthread庫的時候纔會出現,
現象是malloc會死鎖不動,改正的方法是在 __free_to_heap函數最後加一句 "__heap_unlock(heap);" 就可以了。

50、關於目前uClinux for MCF52XX中斷處理的一個BUG糾正
就是要修改原來清除中斷的方式由 |= 改爲 = 即可。
以HHCF5249的IDE驅動爲例:uClinux-dist/linux-2.4.x/include/asm/ide.h
修改的地方僅一行,參見下面加紅加粗代碼:
static IDE_INLINE void
ide_get_lock(
int *ide_lock,
void (*handler)(int, void *, struct pt_regs *),
void *data)
{
#ifdef CONFIG_M5249C3
/* Clear interrupts for GPIO5 */
*((volatile unsigned long *) 0x800000c0) = 0x00002020; 
#endif
}
再看以太網驅動:
uClinux-dist/linux-2.4.x/drivers/net/dm9000x.c修改如下:
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) 函數中:
*((volatile unsigned long *) (MCF_MBAR2+MCFSIM2_GPIOINTCLEAR)) = 0x00004040; 

51、關於HHCF5249讀寫CS2~CS6死機的問題
發現怪現象,無法將CSOR1的數值改爲0x3d80,怎麼改都還是0x3c80,這樣一讀就死機。這時,用MEMORY讀寫工具(user/memtools)mt來手工讀寫這些CPU寄存器地址:
/> mt
Please input your command :>>>
gl 10000090 1
00FF0021
Please input your command :>>>
gw 10000096 1
3C80
Please input your command :>>>
pw 10000096 3d80
Please input your command :>>>
gw 10000096 1
3C80
Please input your command :>>>
gw 10000096 1
3C80
Please input your command :>>>
pw 10000096 3d80
Please input your command :>>>
gw 10000096 1
3C80
經查,在uClinux-dist/linux-2.4.x/arch/m68knommu/platform/5249/HHTECH/crt0_ram.S裏面設置的CSOR1還是正確的0x3d80:
/*
* Setup CS1 for ethernet controller.
* (Setup as per M5249C3 doco).
*/
move.l #0x30000000, %d0 /* CS1 mapped at 0x30000000 */
move.l %d0, 0x8c(%a0)
move.l #0x00ff0021, %d0 /* CS1 size of 16Mb */
move.l %d0, 0x90(%a0)
move.w #0x3d80, %d0 /* CS1 = 16bit port, AA */
move.w %d0, 0x96(%a0)
但在LINUX內核啓動過程中就不知哪裏自動給變成0x3c80了,最後確認是在以太網DM9000驅動中給改掉了,見下面紅字標註的代碼:
#define NEEDCHANGE 1
......
inline void outw(unsigned short value, unsigned long addr)
{
cli();
#if NEEDCHANGE
*(volatile unsigned short*)0x10000096 |=0x0100;
#endif
 
// udelay(10);
*(volatile unsigned short*)addr = value;
#if NEEDCHANGE
*(volatile unsigned short*)0x10000096 &=0xfeff;
#endif
sti();
}
將uClinux-dist/linux-2.4.x/drivers/net/dm9000x.c 文件前面的一行改爲:(原來是1,改爲下面的0)
#define NEEDCHANGE 0
然後重新編譯,重燒即可。
【注意】
並不是所有的版本的dm9000x.c都是這個樣子的,有的就沒有上面的問題。

52、關於init: /bin/boa respawning too fast問題
/etc/inittab文件:由init進程監護執行,保證inittab文件中列出的服務進程任何時候都有一份拷貝在內存中運行。它的作用就在於維護一些系統中非常關鍵的後臺服務進程,使之永遠有一份在運行,即使發生致命錯誤導致進程死掉退出,init進程會負責自動再重新啓動一個。下面給出/etc/inittab文件的內容:
inet:unknown:/bin/inetd 【啓動inet服務】
有時我們在板子啓動後,可看到minicom裏不停打印類似下面的信息:
init: /bin/boa respawning too fast
這就是因爲在板子的/etc/inittab文件裏面有這樣一行:
boa:unknown:/bin/boa 
而你make menuconfig選擇應用程序時又沒有選中boa,導致燒到板子上的/bin目錄裏面沒有boa這個程序,init進程就會不停的試圖啓動boa,但又沒有,它就不停的嘗試,所以纔會有這樣的信息出來。所以,要麼你就把boa編進去,要麼就把/etc/inittab裏面這一行用#號註釋掉,重編重燒後就沒有問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章