---基于公用核心板HHCF5272-K1(華恒公司版權所有)

--------------------------------------------------------------------------------

1. 關于宿主機LINUX的安裝

建議使用RED">

      技術頻道

      華恒COLDFIRE系列嵌入式LINUX開發套件常見問題解答

      恒COLDFIRE系列嵌入式LINUX開發套件常見問題解答
      ---基于公用核心板HHCF5272-K1(華恒公司版權所有)

      --------------------------------------------------------------------------------

      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了。


      問:燒寫時顯示如下信息,但minicom端什么信息也沒有打印出來,而且板子仍然在運行,運行指示仍然正常閃爍?
      在執行./flash的TTY一側,會顯示:
      GNU gdb 4.18
      Copyright 1998 Free Software Foundation, Inc.
      GDB is free software, covered by the GNU General Public License, and you are
      welcome to change it and/or distribute copies of it under certain conditions.
      Type "show copying" to see the conditions.
      There is absolutely no warranty for GDB. Type "show warranty" for details.
      This GDB was configured as "--host=i686-pc-linux-gnu --target=m68k-bdm-elf"...


      這是PC端BDM驅動(linux-bdm.o)的問題,必須安裝正確的驅動(例如華恒光盤提供的)。按CTRL+C結束該進程,用rmmod linux-bdm刪除當前的驅動,用insmod安裝正確版本的驅動再重新執行./flash即可。


      問:燒寫完畢后最后會報如下錯誤:
      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.

      解決辦法:

      在PC機上執行uname -r
      看看當前的內核版本,
      例如:顯示為2.4.5
      ,則修改bdm/driver/linux/Makefile中的CFLAGS一行為如下:
      CFLAGS = -Wall -g -O -pipe -I/usr/src/linux-2.4.5/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宿主機環境配置的問題

      目前主要的問題在于完全安裝的REDHAT7.3沒有提供linuxconf工具軟件,因此無法配置NFS服務器。不過這個問題很容易解決,這需要到http://ftp.boe.tcc.edu.tw/tnc/firewall/下載一個名為:linuxconf-1.25r7-3.i386.rpm的RPM包,然后在REDHAT7.3 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庫。
      【注】

      華恒客戶可發信到support@hhcn.com索取測試代碼。

      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. 關于外設中斷的問題

      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;
      }


      24. 關于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)本地化全中文技術手冊及相關的技術支持(論壇)。

      25. 關于不同內核版本間應用程序移植的問題

      應用程序的移植一般的和內核版本是沒有任何關系的,當然有的應用程序是需要內核支持的,例如pppd等。在2.0.38內核和2.4內核之間互移應用程序,唯一要注意的就是Makefile的寫法:

      其實區別就一句話,就是2.4下面,它把elf2flt作為gcc的一個參數一步完成了,而2.0.38還要分為兩步完成,體現在Makefile上就如下:

      對于2.0.38:

      $(LD) $(LDFLAGS) -o $@.elf $(OBJS) $(LDLIBS)
      $(CONVERT)
      對于2.4.x:

      $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

      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中為其指定保存數據的幾個扇區的起始/結束地址。這中方式也不能適應非常頻繁的寫入。

      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)
      *
      * bkr@cut.de 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 。

      華恒客戶可發信到support@hhcn.com索取相關測試代碼。

      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。

      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命令了。


      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+]跳轉到想要查詢的函數/結構定

      文章版權歸西部工控xbgk所有,未經許可不得轉載。

      主站蜘蛛池模板: 国产美女露脸口爆吞精一区二区| 精品在线视频一区| 亚洲AV美女一区二区三区| 国产一区在线播放| 国精产品一区一区三区免费视频| 久久精品无码一区二区三区日韩| 一区二区三区午夜视频| 无码人妻精品一区二区三区久久 | 日韩精品一区二区三区影院| 日韩av无码一区二区三区| 国产激情无码一区二区| 精品在线一区二区| 亚洲AV噜噜一区二区三区| 亚洲V无码一区二区三区四区观看| 中文字幕一区二区三区人妻少妇 | 日韩一区在线视频| 精品一区二区久久| 99精品久久精品一区二区| 国产日韩精品一区二区三区 | 亚洲永久无码3D动漫一区| 国产精品成人一区二区| 在线免费视频一区二区| 无码国产精品一区二区免费式影视 | 精品视频在线观看一区二区| 国产成人久久精品区一区二区| 国产精品女同一区二区| 亚洲熟妇av一区二区三区| 国产成人精品无人区一区| 日本韩国黄色一区二区三区 | 伊人久久精品无码麻豆一区| 国产精品福利一区二区久久| 精品一区二区高清在线观看| 性盈盈影院免费视频观看在线一区 | 天堂一区人妻无码| 国模无码视频一区二区三区| 国产天堂一区二区综合| 精品女同一区二区三区免费站| 国产精品视频一区国模私拍| 一区二区三区四区视频在线| 日韩精品成人一区二区三区| 精品国产一区二区三区www|