嵌入式C編程實(shí)戰(zhàn)_第1頁
嵌入式C編程實(shí)戰(zhàn)_第2頁
嵌入式C編程實(shí)戰(zhàn)_第3頁
嵌入式C編程實(shí)戰(zhàn)_第4頁
嵌入式C編程實(shí)戰(zhàn)_第5頁
已閱讀5頁,還剩121頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

嵌入式C編程實(shí)戰(zhàn)目錄\h第1章嵌入式系統(tǒng)簡介\h1.1嵌入式計(jì)算機(jī)系統(tǒng)\h1.2應(yīng)用程序和平臺\h1.3復(fù)雜度降低\h1.3.1抽象\h1.3.2結(jié)構(gòu)\h1.3.3層次結(jié)構(gòu)\h1.4硬件?FPGA設(shè)備\h1.4.1軟件\h1.4.2硬件和軟件之間的接口\h1.5軟件開發(fā)工具\(yùn)h1.5.1編譯器\h1.5.2鏈接器\h1.6YouTube的推薦資源\h第2章硬件與軟件的安裝\h2.1軟件(IDE)\h2.2硬件平臺\h2.2.1BeMicroMAX10開發(fā)板\h2.2.2系統(tǒng)時鐘\h2.2.3LED和按鈕\h第3章案例1\h3.1硬件架構(gòu)-案例1A\h3.1.1CPUNiosII\h3.1.2Avalon總線\h3.1.3JTAGUART\h3.2設(shè)計(jì)案例1A\h3.2.1介紹\h3.2.2案例1A:硬件部分\h3.2.3實(shí)現(xiàn)\h3.3設(shè)計(jì)案例1B\h3.3.1理論:調(diào)試、監(jiān)控和仿真\h3.3.2傳統(tǒng)的軟件調(diào)試\h3.3.3案例1B:使用調(diào)試器\h3.3.4案例1B:軟件調(diào)試\h3.4設(shè)計(jì)案例1C:嵌入式C語言開發(fā)\h3.4.1理論:二進(jìn)制格式和ASCII碼\h3.4.2理論:Altera專用軟件“HAL(硬件抽象層)”\h3.4.3理論:內(nèi)存映射\h3.4.4PIO理論(并行輸入/輸出)\h3.4.5理論:C語言中的位操作\h3.4.6理論:使用鍵盤和終端進(jìn)行輸入和輸出\h3.4.7案例1C:內(nèi)存映射與硬件\h3.4.8案例1C:軟件設(shè)計(jì)\h3.4.9小結(jié)\h第4章案例2-添加外部存儲\h4.1存儲\h4.1.1RAM\h4.1.2ROM\h4.2設(shè)計(jì)案例2:添加外部RAM\h4.3小結(jié)\h4.4YouTube資源和網(wǎng)絡(luò)資源推薦\h第5章案例3-編寫設(shè)備驅(qū)動程序\h5.1簡介\h5.2案例規(guī)范\h5.3接口\h5.3.1驅(qū)動程序\h5.3.2寄存器\h5.4軟件-硬件抽象層\h使用硬件抽象層\h5.5設(shè)計(jì)案例3A:編寫設(shè)備驅(qū)動\h5.6將設(shè)備驅(qū)動程序整合到BSP中\(zhòng)h5.7設(shè)計(jì)案例3B:使用tickle文件\h5.8設(shè)備驅(qū)動程序\h5.9小結(jié)\h第6章案例4-C代碼的優(yōu)化\h6.1簡介\h6.2值得考慮的部分\h6.2.1選擇一個優(yōu)秀的算法\h6.2.2編寫簡單明了的代碼\h6.2.3操作\h6.2.4了解編譯器的選項(xiàng)\h6.2.5將C代碼移植到VHDL中\(zhòng)h6.3代碼優(yōu)化技術(shù)\h6.3.1變量\h6.3.2結(jié)構(gòu)體\h6.3.3函數(shù)\h6.3.4條件分支與循環(huán)\h6.3.5指針\h6.4簡單執(zhí)行時間測量技術(shù)\h6.5設(shè)計(jì)案例4:測量C代碼性能\h6.6小結(jié)\h6.7引用\h第7章案例5-輪詢和中斷\h7.1簡介\h7.2軟件輪詢輸入/輸出系統(tǒng)\h7.3設(shè)計(jì)案例5A:硬件架構(gòu)-輪詢系統(tǒng)\h7.4設(shè)計(jì)案例5A:軟件-輪詢系統(tǒng)\h7.5中斷系統(tǒng)\h7.5.1簡介\h7.5.2NiosⅡ處理器的中斷\h7.6設(shè)計(jì)案例5B:中斷系統(tǒng)\h7.7討論\h7.8引用\h7.9YouTube推薦\h第8章案例6-模擬信號處理\h8.1簡介\h8.2嵌入式系統(tǒng)中的模擬信號\h8.2.1ADCs-模擬數(shù)字轉(zhuǎn)換器\h8.2.2逐次逼近\h8.2.3MAX10開發(fā)板上的ADC模塊\h8.2.4LDR-光敏電阻\h8.3設(shè)計(jì)案例6:信號的處理\h8.3.1案例6:產(chǎn)品規(guī)格\h8.3.2案例6:硬件\h8.3.3案例6:實(shí)現(xiàn)\h8.4討論\h8.5引用\h8.6YouTube視頻推薦第1章嵌入式系統(tǒng)簡介1.1嵌入式計(jì)算機(jī)系統(tǒng)圖1.1為兩臺不同的計(jì)算機(jī)。圖1.1兩臺計(jì)算機(jī)大部分人看到圖1.1后,立刻就可以認(rèn)出左邊的機(jī)器是一臺計(jì)算機(jī)。不過,幾乎沒有人會把右側(cè)的機(jī)器看作是計(jì)算機(jī),事實(shí)上,它確實(shí)是一臺貨真價實(shí)的計(jì)算機(jī)。這兩臺看起來截然不同的計(jì)算機(jī)最根本的區(qū)別在于,右側(cè)的計(jì)算機(jī)是嵌入在洗衣機(jī)內(nèi)部的。如果你認(rèn)識到這兩者的差異,就可以將計(jì)算機(jī)分成通用計(jì)算機(jī)和嵌入式計(jì)算機(jī)兩類。1.通用計(jì)算機(jī)通用計(jì)算機(jī)指的是臺式機(jī)、筆記本電腦以及工作站等。通用計(jì)算機(jī)(幾乎)總是配有鍵盤、顯示設(shè)備、硬盤驅(qū)動器,以及用來連接互聯(lián)網(wǎng)的以太網(wǎng)卡這些設(shè)備。這些通用計(jì)算機(jī)都進(jìn)行了優(yōu)化,以便運(yùn)行Windows或者M(jìn)acOS之類的(非實(shí)時的)操作系統(tǒng)。2.嵌入式計(jì)算機(jī)嵌入式計(jì)算機(jī)也可以擁有上述的這些設(shè)備,但通常他們與此不同。嵌入式計(jì)算機(jī)要被安裝在被控系統(tǒng)的內(nèi)部。設(shè)計(jì)嵌入式計(jì)算機(jī)的目的是用來專門完成一個(或者幾個)任務(wù)。圖1.1中右邊的計(jì)算機(jī)就是被設(shè)計(jì)用來實(shí)現(xiàn)多個不同的洗衣程序。因此,這臺計(jì)算機(jī)上不是用來運(yùn)行Windows操作系統(tǒng)的,更不可能被用來玩魔獸世界了。但這并不能改變它是一臺計(jì)算機(jī)的事實(shí),它有著一顆計(jì)算機(jī)的“心”,這顆“心”由CPU、存儲器和一些輸入/輸出單元構(gòu)成。由于嵌入式計(jì)算機(jī)是具有特定功能的專用計(jì)算機(jī),所以當(dāng)和通用計(jì)算機(jī)進(jìn)行參數(shù)方面的比較時,嵌入式計(jì)算機(jī)顯得弱的可憐。無論是兆赫(MegaHertz,MHz)、內(nèi)存空間(以GB計(jì))、每秒百萬個浮點(diǎn)操作(MillionFloating-pointOperationsperSecond,MFLOPs),或者數(shù)據(jù)傳輸速率(以Gbit/s計(jì))這些指標(biāo)的哪一項(xiàng),兩者都無法相提并論。嵌入式計(jì)算機(jī)在成本和功耗方面都進(jìn)行了優(yōu)化。誰都不會需要使用一個主頻高達(dá)5GHz的英特爾酷睿處理器和一個存儲容量達(dá)到5TB的硬盤組成的通用計(jì)算機(jī)來控制洗衣機(jī),因?yàn)檫@樣做意味著巨大的浪費(fèi)(費(fèi)用和能源上的)。通用系統(tǒng)和嵌入式系統(tǒng)的關(guān)系如圖1.2所示。圖1.2通用系統(tǒng)和嵌入式系統(tǒng)的關(guān)系不過,無論是通用計(jì)算機(jī),還是嵌入式計(jì)算機(jī),都具有相同的工作原理,它們都是計(jì)算機(jī),兩者之間的差異僅在于“規(guī)?!?。我們很難給出一個讓所有人都能滿意的關(guān)于嵌入式系統(tǒng)的定義。但是,我們對于這個系統(tǒng)定義現(xiàn)在已經(jīng)取得了一些共識。下面列出的這些應(yīng)用就是常見的嵌入式系統(tǒng)。工業(yè)系統(tǒng):工業(yè)機(jī)器人、控制系統(tǒng)等。汽車系統(tǒng):ABS剎車、傳輸控制等。醫(yī)療儀器控制:掃描儀,植入心臟監(jiān)視器等。數(shù)碼設(shè)備控制:CD播放器、電視遙控器、可編程的自動噴水滅火裝置、家用電器等。下面列出的系統(tǒng)都不能歸類到嵌入式系統(tǒng)。用來進(jìn)行數(shù)據(jù)處理的計(jì)算機(jī)系統(tǒng)。運(yùn)行在PC或者UNIX計(jì)算機(jī)上的軟件系統(tǒng)。用于傳統(tǒng)的商業(yè)或者科學(xué)應(yīng)用的系統(tǒng)。本書對嵌入式系統(tǒng)的定義如下:嵌入式系統(tǒng)指的是專門的軟件、硬件和接口的集合,目的是用來執(zhí)行特定的任務(wù)(如運(yùn)行一臺洗衣機(jī)等)。當(dāng)對嵌入式系統(tǒng)和通用系統(tǒng)計(jì)算機(jī)的產(chǎn)品數(shù)量進(jìn)行比較時,通用系統(tǒng)計(jì)算機(jī)在市場上占有的比例還不到計(jì)算機(jī)總量的0.5%。一個普通的家庭(這里指的是西方國家)通常會擁有30個以上的嵌入式計(jì)算機(jī)和兩個通用型計(jì)算機(jī)。單是一個現(xiàn)代化的汽車,就包含了40~50個嵌入式計(jì)算機(jī)(發(fā)動機(jī)控制、溫度控制、燃油噴射系統(tǒng)、安全氣囊控制、座椅加熱、測量燃油液位、速度、轉(zhuǎn)速、雨水傳感器等)。圖1.3給出了一個嵌入式計(jì)算機(jī)系統(tǒng)組件的實(shí)例。圖1.3嵌入式系統(tǒng)可以包括微處理器以及許多其他組件大多數(shù)情況下,一個嵌入式計(jì)算機(jī)系統(tǒng)并不會包含大型的組件,取而代之的是大量的小型組件。下面列出了一些這種類型的組件。傳感器(如按鈕)。執(zhí)行器(如燈)。A/D和D/A轉(zhuǎn)換器。人機(jī)交互界面。與此相比,典型的通用計(jì)算機(jī)硬件組成部分為硬盤驅(qū)動器、以太網(wǎng)接口、顯示設(shè)備、鍵盤以及鼠標(biāo)。作者點(diǎn)評:時至今日,已經(jīng)無法在通用計(jì)算機(jī)和嵌入式計(jì)算機(jī)之間劃出一條明確的界限了。打個比方,你能準(zhǔn)確地告訴我iPad或者智能手機(jī)是通用計(jì)算機(jī),還是嵌入式計(jì)算機(jī)嗎?下面是一些常用的術(shù)語:美國國家標(biāo)準(zhǔn)協(xié)會C標(biāo)準(zhǔn)(AmericanNationalStandardsInstituteC,ANSIC)ANSIC是美國國家標(biāo)準(zhǔn)協(xié)會對C語言標(biāo)準(zhǔn)制定的規(guī)范。應(yīng)用程序編程接口(ApplicationProgrammingInterface,API)API是由操作系統(tǒng)或者庫文件提供的源代碼接口,可以被調(diào)用,以此支持一些計(jì)算機(jī)程序發(fā)起的服務(wù)請求。中央處理單元(CentralProcessingUnit,CPU)中央處理單元可以是任何一個符合如下定義的硬件。首先,它必須能夠處理數(shù)據(jù);其次,它必須能控制必要的資源對這些數(shù)據(jù)進(jìn)行處理。例如,對兩個數(shù)求和,CPU就需要讀取這兩個數(shù),然后將它們添加到一個處理電路(如ALU)中,最后將得到的結(jié)果寫回。GNU編譯器套件(GNUCompilerCollection,GCC)由GNU開發(fā)的編程語言編譯器集合,可以用來處理多種編程語言。GNU并不等同于UNIX(GNUisNotUNIX,GNU)GNU是一個完全由自由軟件構(gòu)成的計(jì)算機(jī)操作系統(tǒng)。開發(fā)GNU的項(xiàng)目被稱作GNU計(jì)劃。圖形用戶界面(GraphicalUserInterface,GUI)一種用戶界面,通過它可以實(shí)現(xiàn)人類與計(jì)算機(jī)之間以圖形化的圖標(biāo)方式進(jìn)行交互。人機(jī)界面(HumanMachineInterface,HMI)人機(jī)界面用來實(shí)現(xiàn)人與機(jī)器之間的互動。微處理器(MicroProcessor,μP)微處理器是一種通用設(shè)備,它包含著ALU,也就是算術(shù)邏輯單元和控制單元。微處理器通常都是集成在單個芯片上的獨(dú)立設(shè)備,相比微控制器,它包含了更多的資源,并用來完成復(fù)雜運(yùn)算。微控制器(Microcontroller,μC)微控制器擁有一套完整計(jì)算機(jī)系統(tǒng)“集成”的所有必須單元。微控制器可以被稱為“單芯片解決方案”。它通常包括了中央處理單元(CPU)、RAM、EPROM/PROM/ROM、I/O外設(shè)、定時器、中斷控制器。微控制器可以被認(rèn)為是一種特殊形式的更通用的微處理器。它專門用來控制運(yùn)算復(fù)雜度較小的應(yīng)用程序。通用串行總線(UniversalSerialBus,USB)通用串行總線用來實(shí)現(xiàn)和外部設(shè)備通信的通用串行總線標(biāo)準(zhǔn)的接口技術(shù)。1.2應(yīng)用程序和平臺圖1.4所示的應(yīng)用程序和平臺是一個嵌入式計(jì)算機(jī)系統(tǒng)的兩個組成部分。平臺被設(shè)計(jì)用來幫助應(yīng)用程序完成真正的任務(wù)。一個平臺可以是硬件和操作系統(tǒng)的組合,而應(yīng)用程序則是一個軟件。例如,用來控制工業(yè)機(jī)器人的軟件。通常,一些很小的系統(tǒng)中是不需要操作系統(tǒng)的。事實(shí)上,支持應(yīng)用程序的平臺和項(xiàng)目的管理之間存在著聯(lián)系,一些項(xiàng)目中已經(jīng)證實(shí)了這種聯(lián)系的重要性。這意味著如果有一個可以簡化應(yīng)用程序?qū)崿F(xiàn)的平臺,那么就無需再為項(xiàng)目管理付出高昂的代價了。圖1.4操作系統(tǒng)+硬件=平臺,平臺+應(yīng)用程序=嵌入式計(jì)算機(jī)系統(tǒng)性能:如果一個系統(tǒng)不能滿足它的性能需求,就是一個毫無用處的系統(tǒng)。性能參數(shù)通常指的是功能、速度、成本、按時完成工作的能力(實(shí)時性能)和/或電力消耗。功耗:功耗是一個十分重要的指標(biāo),這主要出于以下幾個原因:如果功耗增加了,那么相應(yīng)系統(tǒng)消耗的能量也就增加了。如果功耗很大,就不得不為系統(tǒng)添加昂貴的冷卻系統(tǒng)。對便攜式系統(tǒng),如手機(jī)或其他的手持設(shè)備,功耗的增加意味著電池的使用時間減少。安全:很多的嵌入式系統(tǒng),如醫(yī)療方面或者汽車方面的應(yīng)用程序,都對安全性方面有很高的要求。對于這種類型的應(yīng)用,需要在設(shè)計(jì)的過程中就進(jìn)行廣泛的和可靠的驗(yàn)證和測試,以保證系統(tǒng)能夠按照預(yù)期正常運(yùn)行。有些關(guān)鍵的安全系統(tǒng),如汽車的安全氣囊系統(tǒng)或者支持生命的呼吸系統(tǒng),則需要設(shè)計(jì)為冗余系統(tǒng),這樣在當(dāng)前系統(tǒng)發(fā)生故障時,備份的輔助系統(tǒng)就會接管任務(wù)(并激活警報)。靈活性:在一些情況下,系統(tǒng)的實(shí)現(xiàn)需要靈活性,即可以對系統(tǒng)進(jìn)行修改,以適應(yīng)標(biāo)準(zhǔn)或者功能需求的變化。1.3復(fù)雜度降低正如我們所見,問題的復(fù)雜度正在不斷地增加,我們必須對此做出應(yīng)對??墒?,關(guān)鍵是怎樣才能降低復(fù)雜度呢?本節(jié)將會就這個問題給出一些基本的答案。下面給出了一些“與降低復(fù)雜度相關(guān)的詞匯”。抽象。結(jié)構(gòu)(或體系)。層次結(jié)構(gòu)。1.3.1抽象本書在以下部分定義了最小的組件,有時這些組件也被稱為葉組件。這些組件包括邏輯門、觸發(fā)器、存儲單元(邏輯組件)。其實(shí),還可以將這些組件再分成更小的部分,如晶體管、電阻、電感和電容等最小的不可分割的組成。這些邏輯組件是總線、CPU的組成部分。而總線和CPU又是構(gòu)成多處理器系統(tǒng)的組成部分。組件的復(fù)雜性可以通過抽象層的數(shù)目和元件的數(shù)量來確定。使用抽象層的目的是為了通過隱藏子組件,來降低系統(tǒng)的復(fù)雜性。本書的以下部分定義了不可再分的元件,或者有時也稱為葉元件,如門電路、觸發(fā)器、存儲器(邏輯部件)。其實(shí),可以對一些更小的元件進(jìn)行研究,如晶體管、電阻、電感和電容。這些邏輯部件共同構(gòu)成了總線和CPU,而總線和CPU又共同構(gòu)成了多處理器系統(tǒng)。一個組件的復(fù)雜性可以由它所包含的元件的數(shù)量和抽象層次的數(shù)目決定。抽象層次通過隱藏組件降低復(fù)雜性。軟件組件的抽象層次。機(jī)器代碼?工藝相關(guān)。匯編代碼?工藝相關(guān)。高級語言?工藝無關(guān)。軟件組件?工藝無關(guān)。較高的抽象層次往往被描述為工藝無關(guān)。例如,一個C程序可以被編譯成各種不同的CPU所能執(zhí)行的程序,硬件的VHDL可以被用來對各種不同類型的FPGA進(jìn)行開發(fā)。然而,較高的抽象層次也并非總都是工藝無關(guān)的,一個較高的抽象層次的組件對處理器就是工藝相關(guān)的。1.3.2結(jié)構(gòu)結(jié)構(gòu)用來描述各個組成部分的組件,以及各個組件之間的關(guān)系。嵌入式系統(tǒng)的軟件和硬件都有自己的體系結(jié)構(gòu),如圖1.5所示。圖1.5硬件體系結(jié)構(gòu)框圖這里有一個關(guān)于結(jié)構(gòu)的經(jīng)典法則指出:任何一個人類使用的設(shè)備都不應(yīng)該包含超過72以上的組成部分。但是,一個計(jì)算機(jī)卻可以同時控制大量(數(shù)以百萬計(jì))的組件。1.3.3層次結(jié)構(gòu)現(xiàn)在創(chuàng)建一個結(jié)構(gòu)示意圖,如圖1.6所示。結(jié)構(gòu)中的每一個分支都在延續(xù),直到一個不再可分的節(jié)點(diǎn),這些組節(jié)點(diǎn)有時也被稱作葉節(jié)點(diǎn)。一個組件是一個分支或者是一個不可分的葉結(jié)點(diǎn)。一個葉組件可以是一段沒有調(diào)用任何其他函數(shù)的C代碼,或者是沒有子組件的VHDL代碼。抽象層頂部的部分比底部復(fù)雜。圖1.6抽象層次1.4硬件?FPGA設(shè)備本書中使用的所有案例都是基于靈活性極大的FPGA設(shè)備上完成的。如果一個設(shè)計(jì)師使用單片機(jī)工作時,他僅僅能完成對硬件架構(gòu)的測試。但是,如果選用了FPGA,他將能通過設(shè)置I/O來實(shí)現(xiàn)對所有的從簡單到復(fù)雜的多處理器體系結(jié)構(gòu)的實(shí)驗(yàn)設(shè)計(jì)。因此,F(xiàn)PGA是最適合進(jìn)行應(yīng)用設(shè)計(jì)教育和學(xué)習(xí)的平臺。從邏輯上講,這些FPGA設(shè)備可以按照設(shè)計(jì)師所設(shè)想的任何方式進(jìn)行連接。圖1.7顯示了FPGA設(shè)備的靈活性。左邊是一個簡單的設(shè)計(jì),右邊是一個使用了兩個32位CPU的復(fù)雜設(shè)計(jì)。圖1.7FPGA上的一款簡單設(shè)計(jì)和一款復(fù)雜設(shè)計(jì)可以通過\h/watch?v=gUsHwi4M4xE訪問DaveJones的EEV博客,看到他發(fā)布在YouTube上的視頻(視頻的前15分鐘都是關(guān)于FPGA的),了解FPGA的知識。本書將不會對FPGA進(jìn)行更深入的討論。1.4.1軟件軟件可以使用多種方式來描述。軟件的一種特性就是串行性(順序執(zhí)行),但是,CPU的工作速度很快,因此設(shè)計(jì)師會認(rèn)為多個程序是可以并行執(zhí)行的。這是使用處理硬件組件的相同方式來處理軟件的關(guān)鍵。軟件中的組件包含任務(wù)、線程、過程、函數(shù)、設(shè)備驅(qū)動程序等。圖1.8中說明了如果一個設(shè)計(jì)者在C文件中包含了“#include<stdio.h>”這條語句就可以使用stdio這個庫文件。檢查你的軟件工具支持的各種標(biāo)準(zhǔn)庫文件是一個好主意。圖1.8<stdio.h>庫文件中的一部分組件/函數(shù)一個使用C語言的簡單組件(函數(shù))的例子;“voidprint_pix(alt_u16x,alt_u16y,alt_u8rgb)”,“Print_pix”在坐標(biāo)為(x,y)上的一個像素點(diǎn)寫入了一個“RGB”(紅綠藍(lán))顏色。1.4.2硬件和軟件之間的接口軟件和硬件如同兩個不同的世界,為了管理它們之間的接口,須使用軟件設(shè)備驅(qū)動來控制軟件,使用寄存器來控制硬件。這里有很多的用于軟件和硬件進(jìn)行通信的標(biāo)準(zhǔn)協(xié)議,下面給出了一些實(shí)例。使用軟件向硬件寫入信息。使用軟件從硬件讀取信息。硬件產(chǎn)生到軟件的中斷。如圖1.9所示,接口用來連接不同的組件,它包括各種軟件和硬件。這種類型的軟件叫做設(shè)備驅(qū)動程序。圖1.9硬件和軟件系統(tǒng)的邏輯架構(gòu)各種不同設(shè)備的驅(qū)動程序必須被添加到項(xiàng)目中。圖1.10中給出了UART的設(shè)備驅(qū)動程序被添加到項(xiàng)目后的樣子。在Altera的軟件開發(fā)工具中,所有的工藝相關(guān)部分都保存在板級支持包(BSP)中。應(yīng)用程序軟件是針對產(chǎn)品的。圖1.10“BSP”(板級支持包)和驅(qū)動程序(Altera公司NIOSII)1.5軟件開發(fā)工具現(xiàn)在有很多的軟件開發(fā)語言,如C、C++、ADA、LISP等。軟件的開發(fā)都遵循標(biāo)準(zhǔn)化的過程。程序(源代碼)可以被編譯成目標(biāo)對象可以執(zhí)行的代碼,一些編譯器會將代碼轉(zhuǎn)換為匯編程序。而鏈接器將程序與用到的庫文件和其他一些東西組織在一起,而且所有的基地址都是絕對地址。鏈接器最后產(chǎn)生的可以被下載到目標(biāo)系統(tǒng)并執(zhí)行的機(jī)器代碼,如圖1.11所示。圖1.11軟件開發(fā)層1.5.1編譯器編譯器是一種計(jì)算機(jī)軟件,它的作用是將源程序轉(zhuǎn)換為目標(biāo)程序。通常,通過兩個步驟,就可以將一個C語言編寫的程序轉(zhuǎn)換為目標(biāo)程序。第一步,將C程序轉(zhuǎn)換為匯編程序;第二步,將匯編轉(zhuǎn)換為目標(biāo)程序。目標(biāo)程序不能直接載入到系統(tǒng)中,它還需要和其他目標(biāo)代碼文件鏈接到一起。目標(biāo)程序可能會需要與設(shè)備驅(qū)動程序和其他程序組織在一起,這一點(diǎn)需要由鏈接器來實(shí)現(xiàn)。編譯器不會將符號地址轉(zhuǎn)換為真實(shí)地址。因此,這里即使只有一個目標(biāo)程序,也必須使用鏈接器來完成地址轉(zhuǎn)換。1.5.2鏈接器鏈接器允許將不同的模塊組織成一個程序,而程序員使用鏈接器的歷史可以追溯到1947年。鏈接器的定義鏈接器是一個程序,可以將目標(biāo)程序模塊組織在一起,形成一個可執(zhí)行的程序。簡單地說,就是它將多個文件組合到了一起。目標(biāo)程序是指一種包含了機(jī)器代碼和信息的程序模塊。這些模塊最后需要鏈接器進(jìn)行組裝。大多數(shù)的編程語言(如C)都允許獨(dú)立地進(jìn)行模塊的編寫。這樣做簡化了編程的工作,因?yàn)槟憧梢詫⒁粋€大型的程序分解為多個更小、更容易管理的部分。最后,將這些模塊組合在一起,這是鏈接器的工作。圖1.12給出了程序鏈接的過程。圖1.12在鏈接過程中,目標(biāo)文件和靜態(tài)庫將組裝成新的庫文件或者可執(zhí)行文件elf=可執(zhí)行鏈接格式。1.6YouTube的推薦資源互聯(lián)網(wǎng)是一個無窮無盡的信息來源。本書中大多數(shù)章節(jié)的結(jié)尾部分都會推薦一些Youtube上的視頻,這些視頻與本章的主題有關(guān)。下面給出了幾個推薦的視頻。編譯器的工作原理:\h/watch?v=Kd93n4_5UjM。API是什么?:\h/watch?v=iGkTCObcOqM。SDK是什么?:\h/watch?v=py5H8gKvw44。FPGA是什么?:\h/watch?v=gUsHwi4M4xE。

第2章硬件與軟件的安裝為了完成嵌入式系統(tǒng)的開發(fā)工作,需要一些硬件和軟件。我們使用的軟件通常被稱為“IDE”,即集成開發(fā)環(huán)境。我們將使用Altera公司提供的QuartusII集成開發(fā)環(huán)境,這是一款授權(quán)軟件。Altera公司同時還提供免費(fèi)的網(wǎng)絡(luò)版,可以在他們的網(wǎng)站上(\h/downloads/download-center.html)下載這個版本。為了完成整個設(shè)計(jì)流程,還需要將你的設(shè)計(jì)下載到一些硬件平臺上。這里有很多硬件平臺可供選擇。本書講解的所有實(shí)例使用的都是Arrow電子公司開發(fā)的一款廉價的硬件平臺,這款BeMicroMAX10開發(fā)板的價格大約只有30美元(詳見第2.2節(jié)),這款開發(fā)板上集成了MAX10FPGA的可編程器件,體積只有一張信用卡那么大(\h/item/detail/arrow-development-tools/bemicromax10#RGMn)。本書中的實(shí)驗(yàn)所需要的硬件設(shè)計(jì)文件可以在本書的主頁()上下載。2.1軟件(IDE)從Altera的主頁下載了QuartusII軟件后,得到的將不僅僅是一個IDE。QuartusII可用來實(shí)現(xiàn)對硬件設(shè)計(jì)的編譯,Quartus中也包含實(shí)現(xiàn)軟件的編程和FPGA的配置。Qsys用來設(shè)計(jì)實(shí)現(xiàn)計(jì)算機(jī)結(jié)構(gòu)(CPU、總線、I/O等)。NiosIIEDS(嵌入式設(shè)計(jì)組件套裝)是對NIOSII處理器進(jìn)行軟件開發(fā)項(xiàng)目的開發(fā)工具的名字。NiosIIEDS包含不同的開發(fā)工具,如編輯器、調(diào)試器、終端處理器、編譯器、鏈接器和設(shè)備驅(qū)動程序等。NiosIIEDS中的部分工具和驅(qū)動程序都會在案例中使用。注意,不要和NiosII混淆,NiosII指的是一個處理器的名字,而開發(fā)工具的正式名字是NiosIIEDS,但是有時也會被簡稱為NiosII。ModelSim是一款界面友好的仿真環(huán)境,用于驗(yàn)證硬件設(shè)計(jì)(本書沒有使用)。QuartusIIIDE中還包含一個程序設(shè)計(jì)器,通過這個程序設(shè)計(jì)器,可以將我們的設(shè)計(jì)下載到FPGA。通常,可以通過下面的操作步驟來完成嵌入式系統(tǒng)開發(fā):(1)使用Qsys完成硬件設(shè)計(jì);(2)在ModelSim中進(jìn)行驗(yàn)證;(3)通過Quartus程序設(shè)計(jì)器將硬件設(shè)計(jì)下載到目標(biāo)FPGA中;(4)在Nios中編寫軟件;(5)將軟件下載到目標(biāo)FPGA;(6)對軟件進(jìn)行調(diào)試。不過,本書重點(diǎn)介紹軟件部分(“嵌入式C”),硬件部分不在本書的范圍內(nèi)。我們提供了硬件部分設(shè)計(jì),你可以從我們的網(wǎng)站下載()。每個硬件設(shè)計(jì)通常都包含兩個部分(最少):一個.sof文件和一個.sopcinfo文件。如果想了解關(guān)于硬件設(shè)計(jì)更多的內(nèi)容,可參考《HW/SWEmbeddedFPGASOCDesign2010》(可以在我們的網(wǎng)站上找到它)。2.2硬件平臺2.2.1BeMicroMAX10開發(fā)板圖2.1展示了一個開發(fā)板以及開發(fā)板上的一些硬件。這個開發(fā)板的大小只有50mm×85mm。這是一款A(yù)ltera開發(fā)的FPGA開發(fā)板BeMicroMAX10,它擁有片上非易失性存儲器、片內(nèi)AD轉(zhuǎn)換器以及溫度傳感器。它還具有鎖相環(huán)、硬件乘法器,它還支持軟核CPUNiosII。另外,還可以添加更多的傳感器,這一點(diǎn)我們很快會看到。圖2.1BeMicroMAX10開發(fā)板這個開發(fā)板使用USB電纜供電,電纜還可以用來對FPGA進(jìn)行編程,因此無需再外接電源。但如果有必要,它還提供了一個2.5mm連接器來連接外部電源提供5V的電壓。FPGA本身包含有8000個LE(邏輯單元)、51個M9K存儲塊、24個18×18乘法器、兩個鎖相環(huán)、250kB的Flash存儲器以及250個通用I/O引腳。圖2.2給出了一個FPGA的原理概述以及開發(fā)板上的I/O單元。圖2.2BeMicroMAX10開發(fā)板我們將通過本書中提供的案例來了解各個硬件的細(xì)節(jié),但現(xiàn)在只介紹一下時鐘和最簡單的I/O(LED和按鈕)。2.2.2系統(tǒng)時鐘Max10FPGA也支持Altera軟核CPU——NiosII處理器的執(zhí)行,我們的設(shè)計(jì)將基于這個處理器。所有的任何處理器都需要一個時鐘,我們的處理器NiosII也不例外。本書使用的所有硬件設(shè)計(jì)都可以下載,你無需詳細(xì)理解里面的信息。但這里還是引入這部分內(nèi)容,以便你能更好地了解系統(tǒng)。如圖2.2所示,在開發(fā)板上有一個50MHz的時鐘,而且它與FPGA相連。FPGA還有一對鎖相環(huán),我們將利用這對鎖相環(huán)來創(chuàng)建設(shè)計(jì)工作所需要的時鐘。如果不需要使用外部SDRAM存儲器或者內(nèi)部的AD轉(zhuǎn)換器,那么就只需要一個時鐘(為CPU提供時鐘周期),這里直接使用50MHz的時鐘。不過,當(dāng)向設(shè)計(jì)中添加了外部存儲器(SDRAM)后,就需要通過內(nèi)部的DDR控制器來操作外部存儲器了。DDR表示“雙數(shù)據(jù)速率”,它將SDRAM的讀寫速度提高了2倍。這是因?yàn)镈DR控制器可以在時鐘的上升沿和下降沿分別執(zhí)行一次讀/寫操作。但是,這將需要一個額外的時鐘信號,這個時鐘與系統(tǒng)時鐘的相位差為?90°。為了加快速度,以后也會使用一個PLL來將系統(tǒng)的時鐘頻率增加到80MHz。另外,片內(nèi)ADC需要一個10MHz的時鐘,所示,當(dāng)我們使用ADC時,將不得不調(diào)用第二個PLL來為ADC提供一個10MHz的時鐘。圖2.3給出了為我們更復(fù)雜的設(shè)計(jì)提供的系統(tǒng)時鐘。圖2.3復(fù)雜設(shè)計(jì)的時鐘系統(tǒng)40MHz的時鐘系統(tǒng)可以用于“速度慢”的I/O單位。2.2.3LED和按鈕在第一個案例中的設(shè)計(jì)并沒有使用任何的LED和按鈕。不過,嵌入式系統(tǒng)本身需要一個復(fù)位按鈕。我們將使用BeMicro開發(fā)板上的SW4開關(guān)來實(shí)現(xiàn)這個功能,為了能正確地使用它,需要先了解一些關(guān)于主板上按鈕的信息,同樣,我們也會在這里介紹一下LED燈。首先需要知道FPGA上的引腳是如何分配給硬件的。表2.1給出了硬件與引腳之間的關(guān)系。表2.1FPGA上pin的分配:LED和按鈕開發(fā)板標(biāo)簽信號名稱FPGA引腳名稱D1USER_LED[1]M2D2USER_LED[2]N1D3USER_LED[3]R2D4USER_LED[4]T1D5USER_LED[5]V4D6USER_LED[6]T6D7USER_LED[7]AB4D8USER_LED[8]AA5SW1PB[1]M1SW2PB[2]R1SW3PB[3]V5SW4PB[4]AB550MHzclockSYS_CLKN14“信號名稱”中使用了方括號和數(shù)字的表示方法,實(shí)際上,可以使用任何名字來稱呼它們。注意,表2.1中還包含了向板載的50MHz的時鐘的引腳分配。圖2.4所示為一個按鈕的電路圖。圖2.4按鈕電路圖2.4所示的電路有兩個重要的因果關(guān)系。首先,RC網(wǎng)絡(luò)形成了一個消抖電路(這個按鈕的作用是用來消除信號抖動)。其次,當(dāng)按鈕被按下時,PBX信號變?yōu)檫壿婰OW。因此,如果使用SW4重置系統(tǒng),也就是說,我們希望在按下SW4時系統(tǒng)能夠重置,它必須重置為邏輯LOW。圖2.5給出了LED電路。圖2.5LED電路圖2.5的結(jié)果是:當(dāng)USER_LEDx被設(shè)為LOW時,LED的Dx被打開。

第3章案例13.1硬件架構(gòu)-案例1A本案例中使用的計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)比較簡單,主要由四個部分組成,包括用來處理數(shù)據(jù)的CPU,用來保存數(shù)據(jù)的主存儲器,各種不同類型的外設(shè)和一個用來實(shí)現(xiàn)不同部分之間通信的“總線”,如圖3.1所示。圖3.1案例1A中的微控制器架構(gòu)“案例1A”中硬件架構(gòu)的組成(有時也稱為“IP組件”)包括以下幾個部分。CPU:NiosII(中央處理單元,用來處理數(shù)據(jù))??偩€:Avalon總線(完成各個組成部分之間的通信)。RAM:FPGA內(nèi)部隨機(jī)存取存儲器(用來保存數(shù)據(jù)和程序)。UART:NiosIIJTAGUART(通過printf和scanf來完成與輸入輸出外設(shè)之間的文本通信)。3.1.1CPUNiosII實(shí)際上,一個CPU(中央處理單元)與一個處理器并沒有什么區(qū)別。至少在當(dāng)前市場上銷售的現(xiàn)代電腦中是這樣。因此,本書中的“CPU”與“處理器”是相同的。(擴(kuò)展閱讀:\h/about_6402155_difference-between-cpu-processor_.html)CPU最基本的操作就是執(zhí)行指令,這些指令就是保存在存儲器中的“軟件程序”。CPU按照取指令、分析指令、執(zhí)行指令、結(jié)果寫回4個步驟來完成指令的執(zhí)行。NiosII處理器中的指令一般是32位,這些指令也可以被稱為“機(jī)器碼”。(1)第一步是到內(nèi)存中取出要執(zhí)行的指令。(2)在分析指令階段,要確定CPU所要完成的操作。(3)在執(zhí)行指令階段,使用CPU中的不同組件來完成這些操作。CPU中包含不同類型的子組件,如算術(shù)邏輯單元(ALU)、寄存器等。(4)在結(jié)果寫回階段,如果需要,就將結(jié)果寫回到存儲器中(這個階段不是必須的)。(5)返回到第一步(總是)。圖3.2中所示的NiosII處理器是一個通用的RISC處理器(精簡指令集),它的核心采用了Harvard架構(gòu)。下面會對這一點(diǎn)進(jìn)行細(xì)致討論。一個RISC處理器意味著它可以執(zhí)行的指令集合被壓縮到最小。RISC處理器可以執(zhí)行的指令數(shù)目很少,但是每個指令的完成都只需要一個時鐘周期(jump指令除外)。它的競爭對手“CISC”處理器則擁有一個復(fù)雜的指令集合,因此采用了這種處理器的計(jì)算機(jī)包含有更多(也更復(fù)雜)的指令,而且它們的執(zhí)行所花費(fèi)的時間通常不是一個時鐘周期。圖3.2NiosII處理器的核心和關(guān)鍵部件處理器與一個振蕩器相連,該振蕩器會產(chǎn)生一個高頻的物理時鐘信號。這個時鐘與處理器物理相連,并對所有的事件進(jìn)行同步。如果CPU經(jīng)過優(yōu)化,那么它的每一條指令都應(yīng)該在一個時鐘周期內(nèi)完成。在PC上的CPU的主頻一般以GHz為單位,但是出于減少電力消耗的目的,很多嵌入式系統(tǒng)里的CPU的主頻要比此低得多。時鐘周期越短,CPU每秒可以執(zhí)行的指令(機(jī)器碼)就越多。因此,如果現(xiàn)在擁有一個時鐘頻率為40MHz的CPU,那么這個CPU每秒鐘將可以執(zhí)行4000萬條指令,如果是1GHz的CPU,它每秒可以執(zhí)行10億條指令。NiosII處理器包含以下幾個部分。32位寄存器:寄存器的存取速度非???,但是只能保存少量的數(shù)據(jù)(32位)。中斷控制器:用來處理處理器外部的異步事件,后面的案例中會對此進(jìn)行詳細(xì)介紹。硬件輔助調(diào)試模塊:這個模塊控制處理器的啟動、停止、步進(jìn)和跟蹤算術(shù)邏輯單元,用來實(shí)現(xiàn)數(shù)學(xué)和邏輯功能額外的硬件,以及實(shí)現(xiàn)速度的優(yōu)化。3.1.2Avalon總線總線是一種用來在各種硬件組件之間傳送信息的標(biāo)準(zhǔn)化通道。隨著時間的推移,計(jì)算機(jī)對通信效率的需求越來越高,從而導(dǎo)致如今的總線設(shè)計(jì)十分復(fù)雜,我們可以對不同的總線進(jìn)行分類,從圖3.3中可以看到,這里有串行和并行兩種不同類型的總線。串行總線應(yīng)用在如以太網(wǎng)通信類的環(huán)境中,低成本是這類總線最大的優(yōu)勢。并行總線主要用在高速率的數(shù)據(jù)存取系統(tǒng),如CPU和主存儲器之間。下面重點(diǎn)介紹并行Avalon總線和所謂的“Harvard結(jié)構(gòu)”總線系統(tǒng)。圖3.3總線的主要類別“Harvard結(jié)構(gòu)”中使用各自獨(dú)立的總線來完成對數(shù)據(jù)和指令的傳輸,如圖3.4所示。NiosII處理器中,指令總線用來連接到存儲器。數(shù)據(jù)總線用來連接到I/O和存儲器。但是,兩者與存儲器相連的目的不同,指令總線用來讀取軟件代碼,而數(shù)據(jù)總線用來讀取變量和堆棧。Harvard架構(gòu)的優(yōu)勢在于,它可以同時完成取指令的操作和將數(shù)據(jù)寫入存儲器或者對I/O設(shè)備的讀/寫操作。圖3.4Harvard結(jié)構(gòu)中的兩種總線Harvard結(jié)構(gòu)的劣勢很明顯,它的結(jié)構(gòu)復(fù)雜,造成了資源的浪費(fèi)。和它處于競爭狀態(tài)的馮·諾依曼型則提出了另一種設(shè)計(jì),在這種結(jié)構(gòu)中,數(shù)據(jù)和指令的傳輸共享相同的物理總線。這種結(jié)構(gòu)將資源的浪費(fèi)減到了最小,但是卻造成了速度的下降(因?yàn)椴荒軌蛲瑫r讀取數(shù)據(jù)和指令)。3.1.3JTAGUART通用異步接收器/發(fā)送器負(fù)責(zé)與PC串行通信。PC中有一個JTAG接收器負(fù)責(zé)將串行數(shù)據(jù)轉(zhuǎn)換回并行。計(jì)算機(jī)與FPGA開發(fā)板之間通過JTAG(聯(lián)合測試工作組)協(xié)議進(jìn)行通信。當(dāng)執(zhí)行printf(“hello”)語句時,“hello”就被以ASCII格式發(fā)送到PC的終端窗口上。3.2設(shè)計(jì)案例1A3.2.1介紹本章這個案例的設(shè)計(jì)目標(biāo)是開發(fā)一個簡單的程序,該程序可以在終端窗口打印內(nèi)容為”Hellostudent”的文本,最后將這個程序下載到目標(biāo)硬件平臺,并在平臺上執(zhí)行通過。你所需要下載到FPGA中的硬件(嵌入式系統(tǒng))設(shè)計(jì),都可以在我們的主頁上()下載到,這些設(shè)計(jì)通常包含兩個部分:一個是.sof文件;另一個是.sopcinfo文件。你需要將這些文件下載到自己的項(xiàng)目文件夾中。3.2.2案例1A:硬件部分下載案例1A中的兩個文件(步驟一和步驟二):CASE_1A.sof(硬件程序文件)。embedded_system_case_1a.sopcinfo(微處理器架構(gòu),板級支持包[BSP]的硬件信息)。按照以下步驟進(jìn)行。(1)創(chuàng)建一個文件夾,注意,在給該文件命名時,不能使用空格,例如“C:\...\CASE_1A”。(2)下載硬件設(shè)計(jì)文件:\h/designfiles/BeMicro_MAX_10/HW_CASE_1A.zip(3)下載的文件中包含兩個部分,將文件解壓后保存到一個文件夾中。此外,再創(chuàng)建一個名為Workspace_SW的文件夾。文件結(jié)構(gòu)示例(名稱中沒有空格字符):?…\

?Workspace_SW//所有案例

?CASE_1

■CASE_1//FPGA的硬件編程文件

■embedded_system_case_1a.sopcinfo//C語言開發(fā)工具的硬件信息這里的硬件是一個計(jì)算機(jī)系統(tǒng),它由16KB的存儲器,終端處理器(JTAGUART)和一個32位的RISC處理器(50MHz時鐘頻率)構(gòu)成,如圖3.5所示。圖3.5案例1A中的嵌入式計(jì)算機(jī)體系結(jié)構(gòu)NiosII中的SBT(軟件構(gòu)建工具)需要知道硬件地址在內(nèi)存中的映射。這些硬件包括JTAGUART、RAM存儲器、復(fù)位向量等。所有的這些信息都存儲在.Sopcinfo文件中,NiosII中的SBT工具通過讀取這個文件來了解這些信息。3.2.3實(shí)現(xiàn)主要步驟如下所示。啟動NiosIISBT:啟動軟件(SW)的開發(fā)工具。創(chuàng)建一個新的軟件(SW)項(xiàng)目:使用NiosIISBT創(chuàng)建一個新項(xiàng)目。對硬件進(jìn)行編程(配置):通過USB-Blaster來完成FPGA設(shè)備的編程。下載和執(zhí)行軟件:將“.elf”文件下載到目標(biāo)的內(nèi)部RAM中,然后在NiosIICPU中執(zhí)行該文件。編輯應(yīng)用程序文件hello_world.C:編輯C代碼。這是所有案例的典型開發(fā)步驟。步驟1:啟動NiosIISBT(1)在Windows開始菜單中啟動NiosIISBT(altera/niosIIEDS)。NiosIISBT使用Eclipse作為開發(fā)框架。Eclipse會將項(xiàng)目的狀態(tài)保存在一個工作區(qū)文件夾中,該文件夾獨(dú)立于項(xiàng)目庫。選擇一個工作區(qū)文件夾供書中的案例使用,如圖3.6所示。圖3.6在NiosIISBT中將項(xiàng)目存儲在一個獨(dú)立的文件夾中(單擊OK按鈕)示例(2)圖3.7給出了NiosIISBT圖形化界面。最值得注意的是,當(dāng)前的“項(xiàng)目資源管理器”中顯示了項(xiàng)目中的所有文件,“文件瀏覽器”打開了可以編輯的文件,“終端窗口”用來顯示連接到FPGA開發(fā)板的信息。執(zhí)行語句printf(“hellofromNiosII!\n”)時,該語句將會在“終端窗口”屏幕上顯示出來。圖3.7NiosIISBT圖形化界面步驟2:創(chuàng)建一個新的SW項(xiàng)目(3)按照如下所示的步驟創(chuàng)建一個新的軟件項(xiàng)目:在菜單欄依次選中File>>New>>NiosIIApplicationandBSPfromtemplate,如圖3.8所示。圖3.8NiosIIApplicationandBSPfromTemplate(4)圖3.9展示了Template中的詳細(xì)選項(xiàng),首先要在“SOPCInformationFilename”后面選中項(xiàng)目中的.sopcinfo文件,然后為這個項(xiàng)目起一個名字,如“sw_case_1a”。在“projecttemplate”中選中下面的“HelloWorld”,這個“HelloWorld”模板中包含如下代碼:圖3.9選擇.sopcinfo文件,為項(xiàng)目起名并選中一個Template,單擊“Finish”按鈕

#include<stdio.h>

intmain()

{

printf("HellofromNiosII!\n");

return0;

}

(5)單擊“Finish”(見圖3.9)。NiosIISBT工具會在軟件庫(圖3.9右側(cè)的“項(xiàng)目資源管理器”)中創(chuàng)建兩個文件夾,分別是項(xiàng)目文件夾(應(yīng)用程序)和BSP文件夾(板級支持包)。BSP是硬件和應(yīng)用程序之間的接口,它和硬件聯(lián)系很緊密。而另一個文件夾(項(xiàng)目或者應(yīng)用程序)則與硬件無關(guān)。(6)編輯BSP的屬性,在BSP文件夾上單擊鼠標(biāo)右鍵,然后選中“Properties”?!癗iosIIBSPProperties”選項(xiàng)卡下方顯示了一些BSP的屬性。選中復(fù)選框中的“Reduceddevicedrivers”和“SmallClibrary”選項(xiàng),取消復(fù)選框“SupportC++”選項(xiàng)。單擊“Apply”按鈕,如圖3.10所示。這樣將會最大限度地對代碼進(jìn)行精簡,以使得這些代碼可以載入到內(nèi)部存儲中。(在后面的其他情形中,程序的大小將會超出片上存儲器的容量,到時我們將在硬件設(shè)計(jì)中添加一個外部RAM存儲器。)然后單擊“OK”按鈕,關(guān)閉這個窗口。圖3.10BSP屬性SmallClibrary-選中這個復(fù)選框時,系統(tǒng)將會使用一個經(jīng)過精簡的ANSIC標(biāo)準(zhǔn)庫Newlib。值得注意的是,選中這個復(fù)選框后,printf()系列的函數(shù)[printf(),fprintf(),sprintf()]等都不支持浮點(diǎn)數(shù)表示。精簡后的庫雖然降低了效率,但是卻優(yōu)化了對內(nèi)存的使用。Reduceddevicedrivers-選中這個復(fù)選框時,編譯器將會包括所有支持小型驅(qū)動程序設(shè)備的精簡版驅(qū)動程序。在本例中,JTAGUART將使用一個小型的輪詢式驅(qū)動(默認(rèn)使用中斷式驅(qū)動),相比系統(tǒng)默認(rèn)的驅(qū)動,輪轉(zhuǎn)式驅(qū)動的代碼量較小。(7)通過以下步驟完成項(xiàng)目構(gòu)建:選中Project>>BuildProject(在Project文件夾上單擊鼠標(biāo)右鍵,然后選中“BuildProject”),如圖3.11所示。這個步驟是為了建立硬件驅(qū)動程序的特定部分。圖3.11編譯后的代碼大小為5980B,可用空間為9689B使用源文件(“hello_world.c”)以及一些其他的工具來創(chuàng)建一個可以下載到目標(biāo)存儲器的文件,這個文件命名為“sw_case_1a.elf”。圖3.12分別顯示了計(jì)算機(jī)文件系統(tǒng)和NiosIISBT中的項(xiàng)目庫位置。兩者幾乎是相同的,項(xiàng)目文件都被保存在項(xiàng)目路徑下的software文件夾中。圖3.12Windows計(jì)算機(jī)文件系統(tǒng)和NiosIISBT中的項(xiàng)目文件位置步驟3:編程(配置)硬件FPGA設(shè)備幾乎可以為所有的硬件架構(gòu)進(jìn)行編程(配置)。CASE_1A.sof文件用來配置FPGA中的硬件。配置有時也被稱為編程。Altera’sFPGA將配置數(shù)據(jù)保存在SRAM單元。由于SRAM單元屬于易失閃存,所以SRAM單元在每次加載配置數(shù)據(jù)時必須接通電源。我們可以很容易地將32-bitsCPU、RAM、UART下載到FPGA設(shè)備中,如圖3.13所示。從教學(xué)的角度講,這是一個完美的選擇。設(shè)計(jì)者可以對幾乎所有的計(jì)算機(jī)體系結(jié)構(gòu)和各種類型的CPU進(jìn)行設(shè)計(jì)和下載。另一個好處是,USBBlaster線纜可以用于多種不同的通信活動,如設(shè)備編程、軟件下載、終端窗口通信(通過使用JTAGUART)和調(diào)試。圖3.13通過USBBlaster線纜將案例1A中的硬件架構(gòu)

下載到FPGA設(shè)備并編程步驟如下所示。(8)在NiosSBT中啟動“QuartusIIProgrammer”,如圖3.14所示。圖3.14啟動“QuartusIIProgrammer”(9)配置QuartusII程序的參數(shù)。單擊“AddFile”,打開CASE_1A.sof,如圖3.15所示。圖3.15查找并添加CASE_1A.sof(10)使用案例1A中的架構(gòu)為FPGA設(shè)備編程。單擊“Start”按鈕,一直等待到項(xiàng)目進(jìn)度條到百分之百,如圖3.16所示。圖3.16編程FPGA器件(11)退出,并在詢問是否保存更改時單擊“No”按鈕,如圖3.17所示。圖3.17單擊“No”按鈕現(xiàn)在硬件設(shè)計(jì)已經(jīng)在FPGA設(shè)備中配置好了。下一步就是將軟件下載到16KB的RAM存儲器中。如果關(guān)閉了電源,硬件設(shè)計(jì)將會被FPGA設(shè)備清除掉(RAM單元會丟失配置存儲),導(dǎo)致不得不重新下載。步驟4:下載軟件程序并且執(zhí)行軟件程序(12)在項(xiàng)目目錄上單擊鼠標(biāo)右鍵,然后選擇RunAs->NiosIIHardware。(13)如果出現(xiàn)了連接方面的問題,單擊“RefreshConnections”,然后選擇“run”,如圖3.18所示。圖3.18讀取錯誤信息和解決問題的方法(14)運(yùn)行程序后,結(jié)果如圖3.19所示。圖3.19控制臺窗口(終端窗口)(15)單擊紅色按鈕,可以終止應(yīng)用程序,如圖3.19所示。如果發(fā)生“IDnumber”相關(guān)的問題,在“RunConfigurations”選項(xiàng)卡下面的“SystemIDchecks”部分選中“IgnoremismatchedsystemID”和“Ignoremismatchedsystemtimestamp”復(fù)選框,如圖3.20所示。圖3.20SystemIDchecks步驟5:編輯C代碼(16)在項(xiàng)目文件sw_case_1a上雙擊鼠標(biāo),就可以實(shí)現(xiàn)對應(yīng)用程序“hello_world.c”的編輯,如圖3.21所示。圖3.21打開hello_world.c(17)代碼編輯的范例:

intmain()

{

inttemp,i;

printf("\n\nstart\n");temp=0;

while(1)

{

for(i=0;i<500000;i++);//進(jìn)行循環(huán)

temp=temp+1;

printf("\nHello!:%d",temp);

}

}

(18)保存,編譯并運(yùn)行這個C文件。注意,如果切斷了FPGA開發(fā)板的電力供應(yīng),就不得不再一次使用同一個.sof文件對FPGA編程,然后再下載這個軟件。結(jié)果如圖3.22所示。圖3.22恭喜你!你的第一個在FPGA上開發(fā)的嵌入式計(jì)算機(jī)系統(tǒng)已經(jīng)成功創(chuàng)建了3.3設(shè)計(jì)案例1B設(shè)計(jì)案例1B重點(diǎn)介紹調(diào)試器的使用。NiosIIIDE中提供了一個名為GNUPro的調(diào)試器。在這個案例中,我們將會使用和案例1A中相同的硬件。3.3.1理論:調(diào)試、監(jiān)控和仿真正如大多數(shù)人知道的一樣,世界上不存在完美的程序。調(diào)試程序代碼和維護(hù)工作占了軟件產(chǎn)品開發(fā)的大部分時間和成本。如今,對軟件的調(diào)試和測試工作會占據(jù)開發(fā)時間總成本的80%,甚至更多。為了讓你對花費(fèi)在軟件的調(diào)試和維護(hù)方面的成本有一個了解,這里引用美國商務(wù)部的數(shù)據(jù),根據(jù)NIST(美國國家標(biāo)準(zhǔn)及技術(shù)研究所)所做的從2002年起軟件測試對經(jīng)濟(jì)的影響的報告,僅僅是美國一個國家,每年用于軟件調(diào)試花費(fèi)的金錢就高達(dá)590億美元??赐赀@些天文數(shù)字,你應(yīng)該很清楚地知道在編寫代碼的初期,就盡量減少錯誤的必要性。當(dāng)然,我們都希望能編寫出無差錯的代碼,但是要做到這一點(diǎn)十分困難,我們還有很長的路要走。軟件bug的數(shù)量可以通過代碼重用降到最低,當(dāng)然,這些代碼必須已經(jīng)通過了嚴(yán)格的測試,并且其中的錯誤已經(jīng)基本被發(fā)現(xiàn)。不過,代碼并不是總能被再次利用的,那么擺在你面前就只有很多時候都需要重新編寫代碼。Bug通常產(chǎn)生在項(xiàng)目的早期,在項(xiàng)目某個功能模塊的設(shè)計(jì)階段,并沒有被發(fā)現(xiàn),直到項(xiàng)目已經(jīng)進(jìn)行很久后,比如,對多個模塊進(jìn)行整合時,這時多個模塊互相影響、互相作用,Bug就發(fā)生了。這種Bug的影響是相當(dāng)嚴(yán)重的,因?yàn)榇藭r再去尋找在設(shè)計(jì)階段就存在的問題相當(dāng)困難。而且這種類型的Bug又很難以確定產(chǎn)生的根源。通常,這種錯誤往往有一種傾向,就是經(jīng)常隨機(jī)出現(xiàn),這使得對其進(jìn)行調(diào)試變得更加困難。3.3.2傳統(tǒng)的軟件調(diào)試目前有很多種用來尋找軟件漏洞的方法。一種常用的方法是在代碼中插入調(diào)試打印標(biāo)記,這樣可以在終端窗口打印輸出要進(jìn)行檢查的值或者符號。然而,這種方法有它的缺陷,執(zhí)行調(diào)試打印操作通常要消耗CPU大量的時間。如果這個應(yīng)用程序?qū)r間要求很精確,那么這些調(diào)試打印操作就可能因?yàn)檎加么罅繒r間,從而導(dǎo)致該程序不能再按照預(yù)計(jì)工作。換言之,由于各種事件不能按時執(zhí)行,將會導(dǎo)致它無法完成預(yù)期的工作。一個例子:

voidadd_func(inta,intb)

{

intc;

c=a+b;

print(c);/*打印C的值,來驗(yàn)證它是否正確*/

}

另一種方法與調(diào)試打印方法類似,就是將所要檢查的變量或寄存器的值寫入內(nèi)存中的緩沖區(qū)中。這種方法比在終端窗口打印輸出速度要快,因此對程序各種事件的執(zhí)行時間影響要小得多。這種方法的缺點(diǎn)是,需要在程序中選擇合適的地方插入斷點(diǎn)。必須這樣做才能阻止程序的執(zhí)行,以便實(shí)現(xiàn)對緩沖區(qū)內(nèi)容的檢查。但是,如果這里有很多數(shù)據(jù)需要分析,這種方法將十分麻煩。一個例子:

inta[10];

voidloop_func(void)

{

inta[10];

inti,c;

c=0;

for(i=0;i<10;i++){

a[i]=c;

c++;

}

}//停止并檢查向量a

另外,還有一種補(bǔ)充的方式,就是將值寫入到某種總線分析器。例如,PCI總線分析器能夠?qū)CI總線進(jìn)行采樣,并將某一個時間段產(chǎn)生的所有數(shù)據(jù)保存到內(nèi)存中,然后對這些數(shù)據(jù)進(jìn)行檢查(離線操作)。這種方法和寫入內(nèi)存緩沖區(qū)的方法都只需要消耗最低限度的時間,這是因?yàn)檫@兩種方法需要執(zhí)行的指令只有四五條。相比之下,執(zhí)行打印指令卻需要數(shù)百,甚至上千的匯編指令。所有的這些調(diào)試方法都是通過以某種方式收集數(shù)據(jù)實(shí)現(xiàn)的,因此,在很多案例中表現(xiàn)得并不盡如人意。如果有大量的數(shù)據(jù)需要檢查,這些方法需要的時間可能會長得讓人無法忍受。不過,不能因此就忽視掉這些方法,很多案例中,它們的表現(xiàn)還是十分優(yōu)秀的。為了提高調(diào)試的效率,建議使用某種調(diào)試工具。使用調(diào)試工具的優(yōu)勢在于,相比以前的調(diào)試方法,對變量以及CPU中寄存器的檢查變得十分簡單了。而且一個調(diào)試器可以使用多種不同的方式進(jìn)行工作,這里將給出一個典型的調(diào)試器工作原理的描述說明。3.3.3案例1B:使用調(diào)試器使用調(diào)試器時,是在代碼中插入斷點(diǎn)(見圖3.23)來停止程序的執(zhí)行,并對變量的值和CPU中的寄存器進(jìn)行檢查。只需要在程序窗口左側(cè)欄雙擊鼠標(biāo),就可以添加一個斷點(diǎn),用同樣的方式也可以刪除一個斷點(diǎn)。圖3.23斷點(diǎn)關(guān)于斷點(diǎn)的高級理論(稍后可以再回顧這部分內(nèi)容)下面給出一個例子,在這個例子中,一個假想的斷點(diǎn)被插入到while循環(huán)語句中的第一行。

While(1)

{

i++;

if(i%100==0)

{

..

print("T8\n\r");

}

}

這行代碼對應(yīng)的匯編命令如下所示:

內(nèi)存指令地址

0x00100080ADDR3,R3,1/*將R3中的值加1*/

當(dāng)這個應(yīng)用程序正常運(yùn)行時,這一行將會被執(zhí)行。但是,如果在這里插入一個斷點(diǎn),那么ADD指令將會被一個導(dǎo)致CPU軟中斷的指令所代替。

內(nèi)存指令地址

0x00100080InvalidInstruction/*不可執(zhí)行的指令*/

調(diào)試器移除的指令現(xiàn)在被存放到了一張表中,這張表專門用來存放所有被移除的指令,如圖3.24所示。圖3.24保存的指令當(dāng)CPU執(zhí)行到無效指令(InvalidInstruction)那一行時,就會產(chǎn)生一個軟中斷,然后CPU會跳轉(zhuǎn)到一個專門用來處理此類事件的指定地址。在中斷服務(wù)程序(ISR)引起中斷的原因是:調(diào)試器會在程序的某個位置放置一個無效指令,而執(zhí)行到此時,CPU會轉(zhuǎn)而去執(zhí)行調(diào)試代碼。談到斷點(diǎn)時,不得不考慮一種特殊的情形,這些斷點(diǎn)不能被插入到保存在ROM中的代碼里,這是因?yàn)樵谶@種類型的存儲器中是無法完成指令的交換操作的。編寫代碼時要盡力避免的重要錯誤索引錯誤是一種經(jīng)常發(fā)生的失誤,這種情形主要出現(xiàn)在具有上下限的數(shù)據(jù)結(jié)構(gòu)中,如一個向量。這里我們使用intarray[10]來聲明一個包含了10個元素的數(shù)組,那么移動數(shù)組的索引時,很多人會忘記數(shù)組的第一個位置其實(shí)是[0],最后一個位置是[9],從而導(dǎo)致越界訪問。這樣做將會導(dǎo)致對數(shù)組以外的存儲區(qū)進(jìn)行讀/寫操作,從而破壞了數(shù)組范圍外部的數(shù)據(jù)和代碼。指針錯誤也是一種常見的錯誤,特別是在類似C之類的語言中。實(shí)質(zhì)上,這也是一種違反地址邊界的問題。例如,一個存儲區(qū)域被分配后,就要對指針進(jìn)行限制,讓它只能訪問分配的這段地址區(qū)域,否則數(shù)據(jù)或者代碼就可能會無意中被覆蓋。內(nèi)存分配錯誤和指針錯誤有關(guān),這種錯誤通常是由于分配了很小的內(nèi)存空間,但是卻沒有對指針進(jìn)行限制,從而導(dǎo)致了越界訪問的問題。在循環(huán)語句中或者選擇語句中的條件錯誤可能會導(dǎo)致程序向一個錯誤的方向執(zhí)行。如果循環(huán)的條件定義錯誤了,也可能會出現(xiàn)無限循環(huán)的問題。這里特別值得注意的一點(diǎn)是,一定要慎重對待循環(huán)條件,尤其要仔細(xì)核對邊界的上限和下限。編寫代碼和設(shè)計(jì)循環(huán)條件時,要著重注意這一點(diǎn)。變量初始化錯誤主要是一些變量沒有正確進(jìn)行初始化而導(dǎo)致的錯誤,這可能會出現(xiàn)一些十分奇怪的執(zhí)行結(jié)果。謹(jǐn)慎的態(tài)度是避免此類錯誤所必須的。這里一個典型的變量初始化錯誤例子就是在while循環(huán)中的那個變量i,它的值在每經(jīng)過一次循環(huán)迭代后,都會自動加1(i++)。如果在循環(huán)開始之前忘記了對i進(jìn)行初始化,那么i的值就可能是任意一個數(shù)。如果循環(huán)終止的條件是i==10,當(dāng)循環(huán)開始時,i的值就可能已經(jīng)大于10了,從而導(dǎo)致循環(huán)剛開始就結(jié)束了。輸入數(shù)據(jù)錯誤,意味著需要向函數(shù)輸入的參數(shù)存在著問題。對輸入數(shù)據(jù)進(jìn)行驗(yàn)證十分重要,如果沒有對這些輸入數(shù)據(jù)進(jìn)行測試,那么一旦輸入數(shù)據(jù)存在錯誤,可能就會得到意想不到的結(jié)果。通常我們會認(rèn)為是函數(shù)本身出了什么錯,但其實(shí)發(fā)生錯誤的是輸入的數(shù)據(jù)。邏輯錯誤是一種非常難以克服的錯誤類型。這種類型的錯誤是這樣造成的:設(shè)計(jì)者剛開始為軟件設(shè)計(jì)好了功能,但是在編寫代碼時卻沒能真正地實(shí)現(xiàn)這個功能。代碼的語法可能是完全正確的,但是卻沒有實(shí)現(xiàn)設(shè)計(jì)者的本意。編寫錯誤,也是在語法正確的前提下發(fā)生的錯誤。一個典型的C語言編寫錯誤是,進(jìn)行比較運(yùn)算時,一個設(shè)計(jì)師可能就錯誤地將比較運(yùn)算符寫成賦值運(yùn)算符,比如,本來想寫“if(a==3)”,卻錯誤地寫成了“if(a=3)”。這樣做的結(jié)果,是該語句的結(jié)果將永遠(yuǎn)為真,因?yàn)闂l件a=3的結(jié)果就是TRUE(C語言中,這是一個賦值運(yùn)算,而不是比較運(yùn)算)。編寫一段正確的代碼十分不易,在編寫程序這段路上,你將需要與謹(jǐn)慎、耐心和經(jīng)驗(yàn)為伴。3.3.4案例1B:軟件調(diào)試Nios中的調(diào)試器被稱為GDB(“Gnu調(diào)試器”)。最早的版本被稱為DDD(DataDisplayDebugger),這是一款自由軟件,是由RichardStallman在1986年編寫的。這個調(diào)試器將向你提供一個“內(nèi)部視角”來觀察在程序執(zhí)行時發(fā)生了什么。運(yùn)行時,調(diào)試器主要完成以下3個任務(wù):啟動程序。根據(jù)條件執(zhí)行停止操作。在程序停止時,可以顯示所有的寄存器、存儲器的內(nèi)容以及變量的值等。Nios中的GNU調(diào)試器是通過JTAG接口與硬件通信的,如圖3.25所示。圖3.25通過JTAG和USBblaster的GDB通信按照如下所示的步驟操作。(1)如果之前你已經(jīng)關(guān)閉了FPGA開發(fā)板的電源,那么你將必須再次下載硬件,和上次下載的硬件(CASE_1A.sof)相同。(2)啟動NIOSIISBT工具,并使用同一個工作空間(Workspace_SW)。(3)啟動調(diào)試會話,在項(xiàng)目文件夾的應(yīng)用程序上單擊鼠標(biāo)右鍵,然后選中DebugAs>>NiosIIHardware,如圖3.26所示。調(diào)試器將會啟動,同時通過JTAG電纜建立連接。該程序?qū)趍ain()函數(shù)中的第一行停止。圖3.26用來啟動調(diào)試器的各種不同方法(4)通過單擊窗口頂端右側(cè)的按鈕,可以實(shí)現(xiàn)在C/C++視角與調(diào)試視角之間的切換(如果出現(xiàn)了“switchtodebugperspective”選項(xiàng),要選擇“Yes”),如圖3.27所示。整個過程中,始終可以在不同項(xiàng)目視角之間進(jìn)行切換。圖3.27如果出現(xiàn)了“switchtodebugperspective”選項(xiàng),要選擇“Yes”(5)在任意的代碼行設(shè)置一個斷點(diǎn)。這可以通過在代碼行左側(cè)灰色豎條上雙擊實(shí)現(xiàn)(見圖3.28),斷點(diǎn)在灰色豎條上以圖標(biāo)“”表示。也可以通過單擊按鈕“”來實(shí)現(xiàn)項(xiàng)目在斷點(diǎn)處的執(zhí)行和停止。圖3.28界面一覽(6)使用步進(jìn)按鈕“”實(shí)現(xiàn)代碼的逐步執(zhí)行,如圖3.29所示。圖3.29調(diào)試控制(7)通過選中Window>>ShowView打開一個可以顯示匯編代碼、寄存器和存儲器中內(nèi)容的窗口。這個窗口包含有Variables、Breakpoint、CPURegisters、Memory和Disassembly5個選項(xiàng)卡,如圖3.30所示。圖3.30調(diào)試視圖(C代碼、變量、控制臺以及斷點(diǎn))要確保你已經(jīng)學(xué)會了如何使用這個工具。當(dāng)你的程序不能按照你的預(yù)計(jì)工作時,這個技能將會給你帶來巨大的幫助。如果你在運(yùn)行調(diào)試工具時遇到了一些問題,那么最有可能的原因就是你電腦上的殺毒軟件阻止了調(diào)試工具對程序所做的必要訪問。如果這樣,請?jiān)试S“nios2-gdb-server”的訪問,如圖3.31所示。圖3.31允許“nios2-gdb-server”(抱歉,這里圖片中顯示的是一個使用了瑞典文的系統(tǒng))至此,一個片上(SOC)并支持調(diào)試的計(jì)算機(jī)系統(tǒng)已創(chuàng)建,如圖3.32所示。圖3.32恭喜你:一個片上(SOC)并支持調(diào)試的計(jì)算機(jī)系統(tǒng)已創(chuàng)建3.4設(shè)計(jì)案例1C:嵌入式C語言開發(fā)這種情況下,我們將會深入地以“bit”為單位來操縱數(shù)據(jù)。本章將會介紹二進(jìn)制和ASCII碼、硬件抽象層(HAL)、內(nèi)存映射、并行輸入/輸出(PIO)組件和系統(tǒng)ID組件。3.4.1理論:二進(jìn)制格式和ASCII碼二進(jìn)制是計(jì)算機(jī)使用的。計(jì)算機(jī)同樣也需要依靠指令來完成任務(wù),這些指令會向計(jì)算機(jī)指明如何處理數(shù)據(jù)。工具(鏈接器)將C程序分成數(shù)據(jù)和指令兩個部分。下面來看如何以不同的數(shù)字形式表示各種不同的數(shù)字信號。數(shù)字信號只有“1”或者“0”兩個不同的值。計(jì)算機(jī)中的二進(jìn)制數(shù)常需要轉(zhuǎn)換成十進(jìn)制整數(shù),ASCII格式等。這種情況下,使用4個bit表示二進(jìn)制數(shù)將會更簡單,讀者需要記住數(shù)字和字母在不同進(jìn)制中的含義。一個BeMicro開發(fā)板上的LED采用的就是二進(jìn)制,而軟件調(diào)試器中使用的是十六進(jìn)制,人類偏愛使用的卻是十進(jìn)制,見表3.1。表3.1在不同數(shù)字系統(tǒng)之間的轉(zhuǎn)換十進(jìn)制十六進(jìn)制二進(jìn)制00000011000122001033001144010055010166011077011188100099100110A101011B101112C110013D110114E111015F1111二進(jìn)制和十六進(jìn)制之間很容易進(jìn)行轉(zhuǎn)換,4位的二進(jìn)制數(shù)和1位的十六進(jìn)制之間存在著對應(yīng)的轉(zhuǎn)換關(guān)系,反之亦然。但是,無符號的整數(shù)38就很難直接轉(zhuǎn)換為二進(jìn)制表示。在二進(jìn)制中,每個0或者1根據(jù)所在位置代表不同的值,從右面開始起的第一個位置的值(權(quán)重)為1,下一個位置的值為2,再下一位是4,以此類推,見表3.2。表3.28位的正數(shù)(0~255)位序號十六進(jìn)制值位序號對應(yīng)的十進(jìn)制值0,最低位0~F1122438416*(0~F)165326647,最高位128表3.3給出了一些無符號整數(shù)的轉(zhuǎn)換。表3.3無符號整數(shù)的轉(zhuǎn)換無符號整數(shù)二進(jìn)制十六進(jìn)制10000010100A60001111003C38001001102625511111111FF1281000000080一個ASCII碼是7位或者8位數(shù)字,可以轉(zhuǎn)換為一個字符。這里給出一個8位的例子,以下是英文單詞“WORLD”對應(yīng)的ASCII值0x57(0101_0111)、0x4f、0x52、0x4c和0x44。這里給本書的每位讀者一個建議,你還應(yīng)該進(jìn)一步學(xué)習(xí)如何使用二進(jìn)制表示一個有符號數(shù)和無符號數(shù)。3.4.2理論:Altera專用軟件“HAL(硬件抽象層)”在開始案例1C中的設(shè)計(jì)前,我們需要對Altera的硬件抽象層(HAL)進(jìn)行介紹。設(shè)立硬件抽象層的目的是為了實(shí)現(xiàn)軟件系統(tǒng)的硬件無關(guān),它是一組有用的操作。當(dāng)使用NiosIIIDE創(chuàng)建了一個新的項(xiàng)目后,一個板級支持包(BSP或者bsp)就誕生了。BSP的庫文件中就包含了HAL。本章中進(jìn)行的嵌入式開發(fā)使用到的文件由表3.4列出。這些文件都是設(shè)計(jì)者感興趣的(這些文件都在BSP中)。表3.4頭文件(includefiles)#include<stdio.h>標(biāo)準(zhǔn)的設(shè)備驅(qū)動程序#include<system.h>硬件描述#include<io.h>Lowlevel中對寄存器和存儲器讀寫的宏#include<alt_types.h>獲得更多控制的基本數(shù)據(jù)類型

#include<system.h>

頭文件system.h是根據(jù)選中的“.sopcinfo”文件和BSP中的硬件信息創(chuàng)建的。對于每一個添加到項(xiàng)目中的硬件組件,相關(guān)的信息都被存儲在system.h中的頭文件中。舉個例子,如果一個項(xiàng)目中包含了一個組件“My_timer”,system.h文件中寫入的信息將如下所示:

“MY_TIMER_BASE0x9000”//定義了“MY_TIMER”的基地址

“MY_TIMER_SPAN16”//表明了從基地址起占用了16個位置

//從0x9000到0x9010

下面的例子中給出了system.h配置文件中的一部分:

#defineALT_MODULE_CLASS_My_TimerTimer

#defineMY_TIMER_BASE0x9000

#defineMY_TIMER_IRQ-1

#defineMY_TIMER_IRQ_INTERRUPT_CONTROLLER_ID-1

#defineMY_TIMER_NAME"/dev/My_Timer"

#defineMY_TIMER_SPAN16

#defineMY_TIMER_TYPE"Timer"

#include<io.h>

HAL提供了C語言中讀取指令和寫入指令的宏IORD和IOWR。這兩個宏都使用HAL設(shè)備驅(qū)動程序來訪問硬件設(shè)備寄存器。#include<io.h>定義了這些宏,見表3.5。表3.5HALI/O宏,頭文件io.h宏用途IORD(BASE,REGNUM)從基地址為BASE的設(shè)備中讀取寄存器中偏移量為REGNUM的單元里面的值,寄存器的值在地址總線的范圍內(nèi)IOWR(BASE,REGNUM,DATA)向基地址為BASE的偏移量為REGNUM的寄存器中寫入數(shù)據(jù)DATA,寄存器的值在地址總線的范圍內(nèi)IORD_32DIRECT(BASE,OFFSET)從地址位置為BASE+OFFSET的寄存器中直接讀取32Bit的數(shù)據(jù)IORD_16DIRECT(BASE,OFFSET)從地址位置為BASE+OFFSET的寄存器中直接讀取16Bit的數(shù)據(jù)IORD_8DIRECT(BASE,OFFSET)從地址位置為BASE+OFFSET的寄存器中直接讀取8Bit的數(shù)據(jù)IOWR_32DIRECT(BASE,OFFSET,DATA)往地址位置為BASE+OFFSET的寄存器中直接寫入32Bit的數(shù)據(jù)IOWR_16DIRECT(BASE,OFFSET,DATA)往地址位置為BASE+OFFSET的寄存器中直接寫入16Bit的數(shù)據(jù)IOWR_8DIRECT(BASE,OFFSET,DATA)往地址位置為BASE+OFFSET的寄存器中直接寫入8Bit的數(shù)據(jù)通過這種方式使用HAL擁有很多優(yōu)勢,其中之一就是可以更容易地對代碼進(jìn)行閱讀和管理,另一個優(yōu)勢就是可以在不改變軟件代碼的前提下,將組件移植到不同的NiosCPUs(E,S,F)上。另外,你也不必再為I/O操作中如何實(shí)現(xiàn)讀寫操作所困擾了,這個問題將在后面討論。

#include<alt_types.h>

為了兼容ANSIC,HAL中明確規(guī)定了NiosII中的有符號位和無符號位的8位、16位和32位數(shù)據(jù)類型。Altera建議使用這些類型來代替short和long等。這樣做的好處是將來向新的架構(gòu)移植軟件時,如果新架構(gòu)訪問的數(shù)據(jù)類型必須為8位、16位和32位,軟件仍然可以正常運(yùn)行。這些定義都在你的應(yīng)用程序代碼中的alt_types.h文件中聲明。表3.6對數(shù)據(jù)類型進(jìn)行了總結(jié)。在嵌入式開發(fā)中應(yīng)用這些數(shù)據(jù)類型,可以保證應(yīng)用軟件的強(qiáng)壯性。表3.6alt_types.halt_8signed8bitartypedefsignedcharalt_8;alt_16signed16bitartypedefsignedshortalt_16;alt_32signed32bitartypedefsignedlongalt_32;alt_u8unsigned8bitartypedefunsignedcharalt_u8;alt_u16unsigned16bitartypedefunsignedshortalt_u16;alt_u32unsigned32bitartypedefunsignedlongalt_u32;alt_u64signed64bitartypedeflonglongalt_64;alt_u64unsigned64bitartypedefunsignedlonglongalt_u64;3.4.3理論:內(nèi)存映射內(nèi)存映射是指各種外部設(shè)備在內(nèi)部地址空間的布局,這些外部設(shè)備可以是I/O寄存器、數(shù)據(jù)存儲器和指令存儲器等。圖3.33給出了一個簡單系統(tǒng)內(nèi)存映射的定義。所有的微型計(jì)算機(jī)系統(tǒng)中都使用了內(nèi)存映射技術(shù)。圖3.33總線架構(gòu)和內(nèi)存映射地址總線中包含著地址信息,數(shù)據(jù)總線將會就這個地址進(jìn)行數(shù)據(jù)的讀或者寫操作。數(shù)據(jù)總線還包含了一個用來決定當(dāng)前是讀周期或者寫周期的控制總線。這里僅就這個問題進(jìn)行了簡單的解釋,我們將會在后面對這個問題進(jìn)行詳細(xì)討論。內(nèi)存映射其實(shí)就是一張地址相關(guān)的表,這張表中保存了各個部分對應(yīng)的內(nèi)存地址的信息,如圖3.33所示。在Nios項(xiàng)目中,這部分信息通常保存在system.h文件中。3.4.4PIO理論(并行輸入/輸出)在案例1C中,兩個PIO作為連接總線和數(shù)字引腳之間的輸入和輸出設(shè)備,如圖3.34所示。圖3.34一個簡單的PIO,左邊連接CPU,右邊連接FPGA引腳CPU總線與32位的數(shù)據(jù)寄存器通過PIO進(jìn)行通信。32位寄存器進(jìn)行了內(nèi)存映射,這意味著許多寄存器都具有獨(dú)立的總線地址。圖3.35給出了寄存器與PIO的映射地址之間的關(guān)系。地址是通過PIO進(jìn)行內(nèi)存映射后的基地址與偏移量的和計(jì)算出來的。關(guān)于基地址的信息存儲在system.h頭文件中。圖3.35用于PIO的內(nèi)存地址映射寄存器第一個PIO寄存器是“data”,偏移量為0,如圖3.36所示。數(shù)據(jù)寄存器具有僅輸出模式和僅輸入模式兩種工作模式。向數(shù)據(jù)寄存器中寫入數(shù)據(jù)時,會驅(qū)動輸出端口將數(shù)據(jù)保存在數(shù)據(jù)寄存器中(這是在Qsys中配置的)。從數(shù)據(jù)寄存器中讀取數(shù)據(jù)時,會使用輸入端口返回數(shù)據(jù)(這也是配置在Qsys中的)。圖3.36用于輸入或輸出的PIO數(shù)據(jù)寄存器3.4.5理論:C語言中的位操作當(dāng)我們越來越接近硬件寄存器時,對整數(shù)的位操作也就顯得越來越重要了。本章將講述如何在C語言中對整形變量進(jìn)行位操作。C語言中有6種不同的位運(yùn)算符,這些運(yùn)算符都只能用于整型數(shù)據(jù)的運(yùn)算。這些運(yùn)算符可以組合使用,它們的作用見表3.7。表3.7C語言中的位運(yùn)算符操作符描述&按位與運(yùn)算符│按位或運(yùn)算符^按位異或運(yùn)算符~取反運(yùn)算符>>右移運(yùn)算符<<左移運(yùn)算符通過掩碼修改使用掩碼是一種用來對某一位進(jìn)行修改的通用方法,其中的目標(biāo)位要被標(biāo)記為1,如“0010110

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論