第5節(jié) 使用 HAL開發(fā)應(yīng)用程序_第1頁
第5節(jié) 使用 HAL開發(fā)應(yīng)用程序_第2頁
第5節(jié) 使用 HAL開發(fā)應(yīng)用程序_第3頁
第5節(jié) 使用 HAL開發(fā)應(yīng)用程序_第4頁
第5節(jié) 使用 HAL開發(fā)應(yīng)用程序_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、本章討論基于Altera的硬件抽象層系統(tǒng)庫開發(fā)程序的方法。HAL的API對(duì)于第一次接觸 Nios II處理器的軟件開發(fā)人員是很容易理解的?;贖AL的程序,使用ANSI C標(biāo)準(zhǔn)庫函數(shù) 和運(yùn)行環(huán)境,并且使用HAL API的通用設(shè)備模型來訪問硬件。HAL API的規(guī)范遵照ANSI C 標(biāo)準(zhǔn)庫的函數(shù),盡管ANSI C標(biāo)準(zhǔn)庫和HAL系統(tǒng)庫是相互獨(dú)立的。ANSI標(biāo)準(zhǔn)庫和HAL的緊密集成使得用戶開發(fā)程序時(shí), 可以不用直接調(diào)用HAL系統(tǒng)庫的函數(shù)。 例如, 可以使用ANSI C 標(biāo)準(zhǔn)庫的I/O函數(shù),如printf( )和scanf()來控制字符型的設(shè)備。 6.5.1 Nios II IDE 工程結(jié)構(gòu) 基于HA

2、L系統(tǒng)庫的軟件工程的創(chuàng)建和管理是與Nios III DE緊密聯(lián)系的。這部分討論Nios II IDE工程來理解HAL。圖6-23為Nios II IDE工程結(jié)構(gòu),說明了HAL系統(tǒng)庫的位置,箭頭表示了各個(gè)工程之間的依賴關(guān)系。 基于HAL的Nios II程序包含兩個(gè)Nios II IDE工程,用戶程序是在用戶應(yīng)用工程中,用戶 程序是依賴于獨(dú)立的系統(tǒng)庫工程(HAL system library project)的。 應(yīng)用工程所有的用戶開發(fā)的代碼,可執(zhí)行文件最終由該工程編譯生成。當(dāng)用戶創(chuàng)建應(yīng)用 工程時(shí),Nios II IDE創(chuàng)建HAL系統(tǒng)庫工程。HAL系統(tǒng)庫工程包含所有的用戶程序與硬件的接 口的必要信

3、息。生成可執(zhí)行文件時(shí),所有的和用戶的SOPC Builder系統(tǒng)相關(guān)的HAL驅(qū)動(dòng)程序 都被加入到系統(tǒng)庫工程。HAL設(shè)置作為系統(tǒng)庫的屬性的被保存。系統(tǒng)庫工程依賴SOPC Builder系統(tǒng),SOPC Builder系統(tǒng)由一個(gè).ptf 文件定義,該文件由SOPC Builder生成。Nios II IDE管理HAL系統(tǒng)庫并且更新驅(qū)動(dòng)程序的配置以準(zhǔn)確地反映系統(tǒng) 硬件的變化。如果SOPC Builder系統(tǒng)發(fā)生了改動(dòng)(即.ptf 文件更新了),Nios II IDE會(huì)在下次用戶生成和運(yùn)行應(yīng)用程序時(shí)重新生成HAL系統(tǒng)庫。 這種工程之間的依賴結(jié)構(gòu)使得用戶程序不用隨著硬件改動(dòng)而進(jìn)行修改, 用戶開發(fā)和調(diào)試代碼

4、時(shí)不用擔(dān)心自己的程序是否和目標(biāo)硬件相匹配。簡而言之,基于HAL系統(tǒng)庫的程序總是和目標(biāo)硬件相同步的。 6.5.2 系統(tǒng)描述文件system.h system.h 文件是HAL系統(tǒng)庫的基礎(chǔ),system.h文件提供了完整的Nios II系統(tǒng)硬件的軟件 描述。它的作用是將硬件和軟件設(shè)計(jì)連接起來。對(duì)應(yīng)用程序開發(fā)者來說,不是system.h中所有的信息都是有用的,很少的情況必須要在用戶的C源程序中包含system.h。雖然如此,system.h 能回答這個(gè)最基本的問題:系統(tǒng)中都有什么硬件? system.h文件描述系統(tǒng)中的每個(gè)外設(shè),并提供如下的細(xì)節(jié): 外設(shè)的硬件配置。 外設(shè)的基地址。 中斷請(qǐng)求優(yōu)先級(jí)。

5、外設(shè)的符號(hào)名。 在軟件工程第一次編譯的時(shí)候,Nios II IDE為HAL系統(tǒng)庫工程生成system.h。system.h 內(nèi)容取決于硬件配置和用戶設(shè)置的HAL系統(tǒng)庫的屬性。用戶不要編輯system.h。 下面給出的是從system.h文件中截取出來的一部分代碼, 是關(guān)于定時(shí)器的設(shè)備的預(yù)定義, 其它設(shè)備的定義與定時(shí)器類似。 #define SYS_CLK_TIMER_NAME /dev/sys_clk_timer #define SYS_CLK_TIMER_TYPE altera_avalon_timer #define SYS_CLK_TIMER_BASE 0x00000820 #defin

6、e SYS_CLK_TIMER_SPAN 32 #define SYS_CLK_TIMER_IRQ 1 #define SYS_CLK_TIMER_ALWAYS_RUN 0 #define SYS_CLK_TIMER_FIXED_PERIOD 0 #define SYS_CLK_TIMER_SNAPSHOT 1 #define SYS_CLK_TIMER_PERIOD 10 #define SYS_CLK_TIMER_PERIOD_UNITS ms #define SYS_CLK_TIMER_RESET_OUTPUT 0 #define SYS_CLK_TIMER_TIMEOUT_PULSE_

7、OUTPUT 0 #define SYS_CLK_TIMER_MULT 0.001 #define SYS_CLK_TIMER_FREQ 85000000 #define ALT_MODULE_CLASS_sys_clk_timer altera_avalon_timer 6.5.3 數(shù)據(jù)寬度和 HAL 類型定義 對(duì)于嵌入式處理器,如Nios II處理器,準(zhǔn)確的數(shù)據(jù)的寬度和精度是非常重要的。由于 ANSI C數(shù)據(jù)類型沒有明確地定義數(shù)據(jù)寬度,HAL使用了一套標(biāo)準(zhǔn)的類型定義,支持ANSI C類型,但是數(shù)據(jù)寬度取決于編譯器的約定。頭文件alt_types.h 定義了HAL類型, Table 6-3

8、是HAL的數(shù)據(jù)類型定義。表6-4給出了Altera采用的GNU編譯器的ANSI C的數(shù)據(jù)類型。 6.5.4 UNIX 風(fēng)格的接口 HAL API提供了許多UNIX-風(fēng)格的函數(shù), UNIX風(fēng)格的函數(shù)使得Nios II的新手程序員不 會(huì)感到開發(fā)環(huán)境的陌生,并且可以很容易地將原有的代碼移植到HAL的環(huán)境下運(yùn)行。HAL主要使用這些函數(shù)給ANSI C標(biāo)準(zhǔn)庫提供系統(tǒng)接口。例如,C標(biāo)準(zhǔn)庫調(diào)用的執(zhí)行設(shè)備訪問的函 數(shù)都在stdio.h中進(jìn)行了定義。下面的列表是可用的UNIX風(fēng)格的函數(shù)的完全列表,其中使用最多的是和FILE I/O相關(guān)的函數(shù): _exit( )close( )fstat( )getpid( )ge

9、ttimeofday( )ioctl( )isatty( )kill( )lseek( )open( )read( )sbrk( )settimeofday( )stat( )usleep( )wait( )write( ) 6.5.5 文件系統(tǒng) HAL提供支持UNIX風(fēng)格的文件訪問的機(jī)制。用戶可以在硬件中任何可用的存儲(chǔ)設(shè)備上建立文件系統(tǒng)。用戶能夠在基于HAL的文件系統(tǒng)中訪問文件,可以使用newlib C庫中的文件I/O 函數(shù),(例如, fopen( ), fclose( )和fread( )或使用HAL系統(tǒng)庫提供的UNIX風(fēng)格的文件I/O。HAL提供如下的UNIX風(fēng)格的函數(shù)來進(jìn)行文件的處理:

10、 close( ) fstat( ) ioctl( ) isatty( ) lseek( ) open( ) read( ) stat( ) write( ) HAL將一個(gè)子文件系統(tǒng)注冊(cè)為HAL文件系統(tǒng)的一個(gè)掛載點(diǎn)(mount point)。要訪問一個(gè) 掛載點(diǎn)下的文件,則指向該掛載點(diǎn)對(duì)應(yīng)的文件子系統(tǒng)。例如,如果一個(gè)只讀zip文件子系統(tǒng)(zipfs)被掛載為/mount/zipfs0,zipfs文件子系統(tǒng)處理對(duì)/mount/zipfs0/myfile 進(jìn)行fopen( )的調(diào) 用。 這里沒有當(dāng)前目錄的概念,軟件訪問文件時(shí)必須使用絕對(duì)路徑。HAL文件結(jié)構(gòu)允許用戶 通過UNIX風(fēng)格的路徑名來管理字符

11、型的設(shè)備。HAL將字符型設(shè)備注冊(cè)為HAL文件系統(tǒng)中的節(jié)點(diǎn)。按照約定,system.h中定義設(shè)備節(jié)點(diǎn)的名字按照 前綴 /dev/加上SOPC Builder中分配給硬件的名字,例如,在system.h 文件中,SOPC Builder中的UART外設(shè)uart1的節(jié)點(diǎn)名為/dev/uart1。 下面的代碼給出了從只讀zip文件子系統(tǒng)ozipfs讀字符的操作,這個(gè)文件子系統(tǒng)被注 冊(cè)為HAL文件系統(tǒng)中的一個(gè)節(jié)點(diǎn)。頭文件stdio.hstddef.h和stdlib.h同HAL一起被包含。從文件子系統(tǒng)讀字符的例子 #include #include #include #define BUF_SIZE (1

12、0) int main(void) FILE* fp; char bufferBUF_SIZE; fp = fopen (“/mount/rozipfs/test”, “r”); if (fp = NULL) printf (“Cannot open file.n”); exit (1); fread (buffer, BUF_SIZE, 1, fp); fclose (fp); return 0; 6.5.6 使用字符型設(shè)備 字符型設(shè)備串行地發(fā)送和接收字符。常見的如通用異步收發(fā)器(UART)。字符型設(shè)備在 HAL系統(tǒng)庫中注冊(cè)為節(jié)點(diǎn)。通常,程序?qū)⒁粋€(gè)文件描述符同設(shè)備名聯(lián)系起來,則使用在file

13、.h 中定義的ANSI C文件操作對(duì)文件進(jìn)行讀寫字符。HAL也支持標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤的概念,允許程序調(diào)用stdio.h I/O函數(shù)。標(biāo)準(zhǔn)輸入(Standard Input)、標(biāo)準(zhǔn)輸出(Standard Output)和標(biāo)準(zhǔn)錯(cuò)誤(Standard Error)使用標(biāo)準(zhǔn)輸入(stdin)、 標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)是實(shí)現(xiàn)簡單控制臺(tái)I/O最容易的方法。HAL系統(tǒng)庫在后臺(tái)管理stdin、stdout和stderr,允許用戶通過這些通道發(fā)送和接收字符,而不是管理文件描述符。例如,系統(tǒng)庫將printf()的輸出指向標(biāo)準(zhǔn)輸出,將perror() 指向標(biāo)準(zhǔn)錯(cuò)誤設(shè)備。用戶可以

14、通過在系統(tǒng)庫屬性中的設(shè)置將每一個(gè)通道同一個(gè)特定的硬件設(shè)備聯(lián)系起來。 下面的代碼顯示的是經(jīng)典的Hello World程序,該程序發(fā)送字符到與stdout相關(guān)聯(lián)的設(shè)備。 例子: Hello World #include int main () printf (“Hello world!”); return 0; 當(dāng)使用UNIX風(fēng)格的API,用戶可以使用在unistd.h中定義的文件描述符stdin、stdout和stderr來分別訪問標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤的字符I/O流。unistd.h is 在Nios II EDS中作為newlib C庫的一部分安裝。 對(duì)字符型設(shè)備的通用訪問 訪問字符型

15、設(shè)備 (除了stdin, stdout, or stderr方法),就像打開和寫一個(gè)文件一樣簡單。下 面的代碼演示的寫一條信息到名為uart1的UART設(shè)備。 例子:寫字符到UART #include #include int main (void) char* msg = “hello world”; FILE* fp; fp = fopen (“/dev/uart1”, “w”); if (fp!=NULL) fprintf(fp, “%s”,msg); fclose (fp); return 0; 6.5.7 使用文件子系統(tǒng) HAL的文件子系統(tǒng)通用設(shè)備模型允許使用C標(biāo)準(zhǔn)庫的文件I/O函數(shù)

16、訪問存儲(chǔ)在存儲(chǔ)設(shè)備中的數(shù)據(jù)。例如,Altera的zip只讀文件子系統(tǒng)提供對(duì)存儲(chǔ)在flash存儲(chǔ)器中的文件子系統(tǒng)的只讀訪問。一個(gè)文件按子系統(tǒng)負(fù)責(zé)管理一個(gè)掛載點(diǎn)下面的所有的文件I/O訪問。例如,一個(gè)文件子系統(tǒng)注冊(cè)為掛載點(diǎn) /mnt/rozipfs ,該目錄下的所有的文件訪問,如fopen(“/mnt/rozipfs/myfile”, “r”),定向?yàn)樵撐募酉到y(tǒng)。如同字符型設(shè)備,用戶可以在file.h 中定義的使用C文件I/O函數(shù)處理文件子系統(tǒng)中的文件。如,fopen()和fread()。 6.5.8 使用定時(shí)器設(shè)備 定時(shí)器設(shè)備是可以計(jì)數(shù)時(shí)鐘的硬件設(shè)備,并可以產(chǎn)生周期性的中斷請(qǐng)求。用戶可以使用定時(shí)

17、器設(shè)備提供一些和時(shí)間相關(guān)的設(shè)備,如HAL系統(tǒng)時(shí)鐘、報(bào)警器、和時(shí)間測量。使用定時(shí)器設(shè)備,Nios II處理器系統(tǒng)在硬件上必須包含一個(gè)定時(shí)器外設(shè)。HAL API提供兩種定時(shí)器設(shè)備的驅(qū)動(dòng)程序: 系統(tǒng)時(shí)鐘驅(qū)動(dòng)這種驅(qū)動(dòng)支持報(bào)警(alarms),用戶在調(diào)度程序會(huì)用到。 時(shí)間標(biāo)記驅(qū)動(dòng)程序該驅(qū)動(dòng)程序支持高精度的時(shí)間測量。 一個(gè)單獨(dú)的定時(shí)器外設(shè)可以作為一個(gè)系統(tǒng)時(shí)鐘或是時(shí)間標(biāo)記,但是不能兼顧。HAL特定 的訪問定時(shí)器設(shè)備的API函數(shù)在sys/alt_alarm.h和sys/alt_timestamp.h中定義。.系統(tǒng)時(shí)鐘驅(qū)動(dòng)程序HAL系統(tǒng)時(shí)鐘的驅(qū)動(dòng)程序提供周期的 “心跳節(jié)拍”(“heartbeat”),使得系統(tǒng)時(shí)

18、鐘按照每 一個(gè)節(jié)拍進(jìn)行遞增。軟件可以使用系統(tǒng)時(shí)鐘設(shè)備來在指定的時(shí)間執(zhí)行函數(shù),并且可以獲得時(shí)序信息。用戶通過在Nios II IDE的系統(tǒng)庫屬性中設(shè)置來選擇指定的定時(shí)器外設(shè)作為系統(tǒng)時(shí)鐘設(shè)備。 HAL提供如下的標(biāo)準(zhǔn)的UNIX函數(shù)的實(shí)現(xiàn):gettimeofday()、settimeofday()和times()。這些函數(shù)返回的時(shí)間是基于HAL系統(tǒng)時(shí)鐘的。系統(tǒng)庫時(shí)鐘測量時(shí)間是以“ticks”為單位的。對(duì)于要和軟件、硬件都打交道的嵌入式工程師,不要將HAL系統(tǒng)時(shí)鐘和驅(qū)動(dòng)Nios II 處理器的時(shí)鐘信號(hào)混淆。HAL系統(tǒng)時(shí)鐘的滴答”ticks”是要遠(yuǎn)大于硬件系統(tǒng)時(shí)鐘的。system.h d定義了時(shí)鐘的頻率。

19、運(yùn)行時(shí),用戶可以調(diào)用alt_nticks()函數(shù)來獲得系統(tǒng)時(shí)鐘的當(dāng)前值。該函數(shù)返回自從系統(tǒng)復(fù)位之后經(jīng)歷的時(shí)間。用戶能獲得系統(tǒng)時(shí)鐘速率,通過調(diào)用函數(shù)alt_ticks_per_second()。HAL定時(shí)器驅(qū)動(dòng)程序在創(chuàng)建系統(tǒng)時(shí)鐘的實(shí)例時(shí)初始化其頻率。標(biāo)準(zhǔn)的UNIX函數(shù)gettimeofday()可以獲得當(dāng)前的時(shí)間。用戶必須首先通過調(diào)用settimeofday()函數(shù)來校正時(shí)間。而且,用戶可以使用times()函數(shù)來或的已經(jīng)發(fā)生的滴答數(shù)目信息。這些函數(shù)的原型在times.h中。 報(bào)警(Alarm) 用戶可以注冊(cè)在指定的時(shí)刻執(zhí)行的函數(shù)使用HAL alarm工具。軟件程序注冊(cè)一個(gè)報(bào)警通過調(diào)用函數(shù)alt

20、_alarm_start(): int alt_alarm_start (alt_alarm* alarm, alt_u32 nticks, alt_u32 (*callback) (void* context), void* context); 在經(jīng)過了n個(gè)ticks之后函數(shù)callback調(diào)用。當(dāng)調(diào)用發(fā)生時(shí),輸入?yún)?shù)context作為輸入變量傳遞給callback。alt_alarm_start()初始化輸入變量alarm所指向的結(jié)構(gòu)。用戶不必去初始化它。 callback函數(shù)能夠復(fù)位alarm。注冊(cè)的callback函數(shù)的返回值是直到下一個(gè)callback函數(shù)調(diào)用的tick的數(shù)目。返回值

21、為0,表示alarm應(yīng)該停止。用戶可以通過調(diào)用alt_alarm_stop()手動(dòng)取消一 個(gè)alarm。Alarm的callback函數(shù)是在中斷的語境(context)中執(zhí)行的,這強(qiáng)加了函數(shù)的限制,用戶必須觀察何時(shí)寫alarm callback。 下面的代碼片段演示了為周期為1秒的callback注冊(cè)一個(gè)alarm。 例:使用周期的Alarm Callback函數(shù) #include #include #include “sys/alt_alarm.h” #include “alt_types.h” /* * The callback function. */ alt_u32 my_alarm_

22、callback (void* context) /* This function will be called once/second */ return alt_ticks_per_second(); . /* The alt_alarm must persist for the duration of the alarm. */ static alt_alarm alarm; . if (alt_alarm_start (&alarm, alt_ticks_per_second(), my_alarm_callback, NULL) 0) printf (“No system clock

23、 availablen”); 時(shí)間標(biāo)記(timestamp)驅(qū)動(dòng)程序 有些時(shí)候,用戶想測量時(shí)間間隔,精度要求比HAL系統(tǒng)時(shí)鐘提供的要高。HAL使用時(shí) 間標(biāo)記驅(qū)動(dòng)程序提供高分辨率的定時(shí)函數(shù)。時(shí)間標(biāo)記驅(qū)動(dòng)函數(shù)提供單調(diào)的增加的計(jì)數(shù)器,用 戶可以采樣來獲得定時(shí)信息。在系統(tǒng)中,HAL只支持一個(gè)定時(shí)標(biāo)記驅(qū)動(dòng)程序。用戶可以通過在Nios II IDE中通過設(shè)置系統(tǒng)庫的屬性來選擇一個(gè)指定的硬件定時(shí)器外設(shè)作為時(shí)間標(biāo)記設(shè)備。 如果有時(shí)間標(biāo)記驅(qū)動(dòng)程序,函數(shù)alt_timestamp_start()和alt_timestamp()可用。Altera提供的時(shí)間標(biāo)記驅(qū)動(dòng)程序使用用戶在系統(tǒng)庫屬性中選擇的定時(shí)器。調(diào)用函數(shù)al

24、t_timestamp_start() 啟動(dòng)計(jì)數(shù)器,接下來調(diào)用alt_timestamp(),則返回時(shí)間標(biāo)記計(jì)數(shù)器的當(dāng)前值。再次調(diào)用alt_timestamp_start()則復(fù)位計(jì)數(shù)器為0。當(dāng)計(jì)數(shù)器的值達(dá)到232 1時(shí),時(shí)間標(biāo)記驅(qū)動(dòng)的行為沒有定義。調(diào)用函數(shù)alt_timestamp_freq(),用戶可以獲得時(shí)間標(biāo)記計(jì)數(shù)器增加的速率。該速率典型值為Nios II處理器運(yùn)行的硬件頻率,通常是每秒鐘幾百萬次。時(shí)間標(biāo)記驅(qū)動(dòng)程序在alt_timestamp.h頭文件中定義。 下面的代碼片段展示的是使用時(shí)間標(biāo)記設(shè)備來測量代碼的執(zhí)行時(shí)間。 例:使用時(shí)間標(biāo)記來測量代碼的執(zhí)行時(shí)間 #include #inc

25、lude “sys/alt_timestamp.h” #include “alt_types.h” int main (void) alt_u32 time1; alt_u32 time2; alt_u32 time3; if (alt_timestamp_start() 0) printf (“No timestamp device availablen”); else time1 = alt_timestamp(); func1(); /* first function to monitor */ time2 = alt_timestamp(); func2(); /* second fu

26、nction to monitor */ time3 = alt_timestamp(); printf (“time in func1 = %u ticksn”, (unsigned int) (time2 time1); printf (“time in func2 = %u ticksn”, (unsigned int) (time3 time2); printf (“Number of ticks per second = %un”, (unsigned int)alt_timestamp_freq(); return 0; 6.5.9 使用 flash 設(shè)備 HAL提供對(duì)非易失性fl

27、ash存儲(chǔ)器設(shè)備的通用模型支持。Flash存儲(chǔ)器使用特殊的編程協(xié)議來存儲(chǔ)數(shù)據(jù)。HAL API提供寫數(shù)據(jù)到flash的函數(shù)。例如,用戶可以使用這些函數(shù)實(shí)現(xiàn)基于flash的文件子系統(tǒng)。 HAL API也提供讀flash的函數(shù),盡管通常不是必須的。對(duì)大多數(shù)flash設(shè)備,當(dāng)對(duì)其進(jìn)行 讀操作時(shí),程序?qū)lash存儲(chǔ)器空間看成簡單的存儲(chǔ)器,不需要調(diào)用特殊的HAL API函數(shù)。如果flash設(shè)備具有特殊的讀數(shù)據(jù)的協(xié)議,如Altera EPCS串行配置設(shè)備,用戶必須使用HAL API進(jìn)行讀寫數(shù)據(jù)。 下面介紹flash設(shè)備模型的HAL API。下面的兩個(gè)API提供不同的層次flash訪問。 簡單flash訪問

28、函數(shù)寫緩沖器數(shù)據(jù)到flash和從flash讀數(shù)據(jù)都是以分區(qū)(block)的層次。 在寫數(shù)據(jù)時(shí),如果緩沖器比一個(gè)完整的分區(qū)小的話,這些函數(shù)擦除原來存在于flash中的在新寫入的數(shù)據(jù)之上和之下的數(shù)據(jù)。 精細(xì)flash訪問函數(shù)寫數(shù)據(jù)到flash和從flash讀數(shù)據(jù)都是以緩沖器的層次。在寫數(shù)據(jù)到 flash時(shí),如果緩沖器比完整的分區(qū)小,這些函數(shù)會(huì)保留之前的存在于flash之中的在新寫 入的數(shù)據(jù)之上和之下的數(shù)據(jù)。這個(gè)功能通常在管理文件子系統(tǒng)時(shí)需要。訪問flash設(shè)備的API函數(shù)定義sys/alt_flash.h。簡單Flash訪問 該接口包含函數(shù):alt_flash_open_dev()、alt_wri

29、te_flash()、alt_read_flash()和 alt_flash_close_dev()。用戶調(diào)用alt_flash_open_dev()函數(shù)來打開一個(gè)flash設(shè)備,該函數(shù)返回一個(gè)flash設(shè)備的文件句柄。該函數(shù)需要一個(gè)單獨(dú)的變量,就是flash設(shè)備的名字,設(shè)備名在system.h中定義。當(dāng)獲得了句柄,用戶可以使用alt_write_flash()函數(shù)寫數(shù)據(jù)到flash設(shè)備。原型為: int alt_write_flash(alt_flash_fd* fd, int offset, const void* src_addr, int length ) 調(diào)用該函數(shù),寫數(shù)據(jù)到由句柄f

30、d標(biāo)識(shí)的flash設(shè)備。驅(qū)動(dòng)程序?qū)憯?shù)據(jù)從flash設(shè)備的基地址偏移offset開始。 寫入的數(shù)據(jù)來自src_addr指向的地址, 寫入的數(shù)據(jù)量為length。 alt_read_flash() 函數(shù)用來從flash設(shè)備讀數(shù)據(jù)。原型為: int alt_read_flash( alt_flash_fd* fd, int offset, void* dest_addr, int length ) 調(diào)用alt_read_flash()從fd標(biāo)識(shí)的flash設(shè)備讀數(shù)據(jù),地址為flash的基地址偏移offset。該函 數(shù)寫數(shù)據(jù)到dest_addr指向的地址,數(shù)據(jù)量為length。對(duì)大多數(shù)flash設(shè)備,

31、用戶訪問時(shí)可以按照標(biāo)準(zhǔn)的存儲(chǔ)器進(jìn)行,不必要使用alt_read_flash()。函數(shù)alt_flash_close_dev()需要一個(gè)文件句柄來關(guān)閉設(shè)備。函數(shù)的原型為:void alt_flash_close_dev(alt_flash_fd* fd ) 下面的代碼顯示簡單flashAPI函數(shù)的使用,訪問的flash設(shè)備名為/dev/ext_flash,在 system.h中定義。 例:使用簡單Flash API函數(shù) #include #include #include “sys/alt_flash.h” #define BUF_SIZE 1024 int main () alt_flash_

32、fd* fd; int ret_code; char sourceBUF_SIZE; char destBUF_SIZE; /* Initialize the source buffer to all 0xAA */ memset(source, 0xAA, BUF_SIZE); fd = alt_flash_open_dev(“/dev/ext_flash”); if (fd!=NULL) ret_code = alt_write_flash(fd, 0, source, BUF_SIZE); if (ret_code=0) ret_code = alt_read_flash(fd, 0,

33、dest, BUF_SIZE); if (ret_code=0) /* * Success. * At this point, the flash is all 0xAA and we * should have read that all back into dest */ alt_flash_close_dev(fd); else printf(“Cant open flash devicen”); return 0; 擦除分區(qū) 通常,flash存儲(chǔ)器被分成許多分區(qū)(block)。alt_write_flash()函數(shù)在寫數(shù)據(jù)之前,可能 需要先擦除一個(gè)分區(qū)的內(nèi)容。 這種情況下, 該函數(shù)不做

34、任何保留分區(qū)中已存在的內(nèi)容的工作, 這將導(dǎo)致不期望的數(shù)據(jù)擦除。 如果用戶希望保持已有的flash存儲(chǔ)器內(nèi)容, 使用精細(xì)flash函數(shù)。 精細(xì)Flash訪問 精細(xì)flash訪問的函數(shù)對(duì)寫flash的內(nèi)容提供完全的控制。alt_get_flash_info()、 alt_erase_flash_block()和alt_write_flash_block()。從flash存儲(chǔ)器的本質(zhì)上來說,用戶不能擦除 一個(gè)分區(qū)中單獨(dú)的一個(gè)地址。用戶一次必須擦除整個(gè)分區(qū)。因此要改變一個(gè)分區(qū)內(nèi)特定的位置的內(nèi)容,而不改變分區(qū)內(nèi)其它位置的內(nèi)容,用戶必須先讀出分區(qū)的整個(gè)內(nèi)容到緩沖器中, 在其中改變相應(yīng)的內(nèi)容, 擦除flas

35、h分區(qū), 最后, 將整個(gè)分區(qū)內(nèi)容寫回到flash存儲(chǔ)器。 精細(xì)flash 訪問函數(shù)自動(dòng)化上述的過程。 alt_get_flash_info()函數(shù)獲得擦除區(qū)域的數(shù)目,每個(gè)區(qū)域內(nèi)分區(qū)的數(shù)目,每個(gè)分區(qū)的大小。函 數(shù)原型為: int alt_get_flash_info( alt_flash_fd* fd, flash_region* info, int* number_of_regions) 如果函數(shù)調(diào)用成功,返回number_of_regions指向的地址,包含有flash存儲(chǔ)器中擦除區(qū)域 的數(shù)目,*info指向flash_region結(jié)構(gòu)的數(shù)組。數(shù)組是文件描述符的一部分。 flash_regi

36、on結(jié)構(gòu)在sys/alt_flash_types.h中定義,其類型定義為: typedef struct flash_region int offset; /* Offset of this region from start of the flash */ int region_size; /* Size of this erase region */ int number_of_blocks; /* Number of blocks in this region */ int block_size; /* Size of each block in this erase region */

37、 flash_region; 調(diào)用alt_get_flash_info()獲得的信息,用戶能夠擦除或編程flash中的單個(gè)分區(qū)。 alt_erase_flash()函數(shù)擦除flash中一個(gè)單獨(dú)的分區(qū)。其原型為: int alt_erase_flash_block( alt_flash_fd* fd, int offset, int length) flash存儲(chǔ)器由句柄fd標(biāo)識(shí),分區(qū)由相對(duì)于flash的起始地址的offset標(biāo)識(shí),分區(qū)的大小通過 length傳遞。 alt_write_flash_block()函數(shù)寫flash存儲(chǔ)器中一個(gè)單獨(dú)的分區(qū)。其原型為: int alt_write_fl

38、ash_block( alt_flash_fd* fd, int block_offset, int data_offset, const void *data, int length) 該函數(shù)寫由句柄fd標(biāo)識(shí)的flash存儲(chǔ)器,寫數(shù)據(jù)到相對(duì)于flash基地址偏移block_offset處,該函數(shù)寫由data指向的位置起始length長度的字節(jié)。下面的代碼演示的是精細(xì)flash訪問的函數(shù)。 例:使用精細(xì)Flash訪問API函數(shù) #include #include sys/alt_flash.h #define BUF_SIZE 100 int main (void) flash_region*

39、 regions; alt_flash_fd* fd; int number_of_regions; int ret_code; char write_dataBUF_SIZE; /* Set write_data to all 0xa */ memset(write_data, 0xA, BUF_SIZE); fd = alt_flash_open_dev(EXT_FLASH_NAME); if (fd) ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); if (number_of_regions & (regi

40、ons-offset = 0) /* Erase the first block */ ret_code = alt_erase_flash_block(fd, regions-offset, regions-block_size); if (ret_code) /* * Write BUF_SIZE bytes from write_data 100 bytes into * the first block of the flash ret_code = alt_write_flash_block ( fd, regions-offset, regions-offset+0x100, wri

41、te_data, BUF_SIZE ); return 0; 6.5.10 使用 DMA 設(shè)備 HAL提供直接存儲(chǔ)器訪問的設(shè)備抽象模型。 這些外設(shè)執(zhí)行從數(shù)據(jù)源到目的地的大批量的 數(shù)據(jù)傳輸。源和目的地可以是存儲(chǔ)器或其它的設(shè)備,如以太網(wǎng)連接。在HAL DMA設(shè)備模型 中,DMA傳輸屬于一下兩種分類之一:發(fā)送或接收。因此,HAL提供兩個(gè)設(shè)備驅(qū)動(dòng)來實(shí)現(xiàn)發(fā)送通道和接收通道。發(fā)送通道從數(shù)據(jù)源的緩沖器獲得數(shù)據(jù),發(fā)送數(shù)據(jù)到目的設(shè)備。接收通道接收數(shù)據(jù),并將數(shù)據(jù)忖道目的緩沖器中。取決于底層的硬件實(shí)現(xiàn),軟件可能只能訪問兩中 端點(diǎn)中的一個(gè)。圖6-24顯示了三種基本的DMA傳輸。存儲(chǔ)器之間的數(shù)據(jù)拷貝同時(shí)包括接收 和發(fā)送

42、DMA通道。 訪問DMA設(shè)備的API在sys/alt_dma.h中定義。DMA設(shè)備操作物理存儲(chǔ)器的內(nèi)容,因此, 當(dāng)讀和寫數(shù)據(jù)時(shí),用戶必須考慮緩存的交互。 DMA發(fā)送通道 DMA發(fā)送請(qǐng)求使用DMA發(fā)送句柄進(jìn)行排隊(duì)。要獲得一個(gè)句柄, 使用函數(shù) alt_dma_txchan_open()函數(shù)。該函數(shù)需要一個(gè)變量,要使用的設(shè)備名字,在system.h中定義。 下面的代碼展示的是怎樣獲得DMA發(fā)送設(shè)備dma_0的句柄。 例:獲得DMA設(shè)備的文件句柄 #include #include “sys/alt_dma.h” int main (void) alt_dma_txchan tx; tx = alt_

43、dma_txchan_open (“/dev/dma_0”); if (tx = NULL) /* Error */ else /* Success */ return 0; 用戶可以使用該句柄通過函數(shù)alt_dma_txchan_send()來遞交一個(gè)發(fā)送請(qǐng)求。該函數(shù)原型 為: typedef void (alt_txchan_done)(void* handle); int alt_dma_txchan_send (alt_dma_txchan dma, const void* from, alt_u32 length, alt_txchan_done* done, void* handl

44、e); 調(diào)用alt_dma_txchan_send()向通道dma遞交發(fā)送請(qǐng)求。變量length指定要發(fā)送的字節(jié)數(shù), 變量from 指定源地址。函數(shù)在整個(gè)DMA傳輸結(jié)束之前返回。返回值指示請(qǐng)求是否成功,并排入隊(duì)列。負(fù)的返回值表示請(qǐng)求失敗。當(dāng)傳輸結(jié)束,函數(shù)done被調(diào)用,提供通知。兩個(gè)附加的函數(shù)用來操控DMA發(fā)送通道:alt_dma_txchan_space()和 alt_dma_txchan_ioctl()。alt_dma_txchan_space()函數(shù)返回還有多少個(gè)發(fā)送請(qǐng)求可以加入到發(fā) 送隊(duì)列中去。alt_dma_txchan_ioctl()函數(shù)執(zhí)行發(fā)送設(shè)備中與設(shè)備相關(guān)的操控。 如果使用A

45、ltera Avalon DMA設(shè)備發(fā)送到硬件設(shè)備(不是存儲(chǔ)器到存儲(chǔ)器的傳輸),調(diào)用 alt_dma_txchan_ioctl()函數(shù),請(qǐng)求變量設(shè)成ALT_DMA_TX_ONLY_ON。 DMA接收通道 DMA 接收通道的工作方式同DMA發(fā)送通道相似。軟件使用alt_dma_rxchan_open()函數(shù)可以獲得DMA接收通道的句柄。 用戶然后可以使用alt_dma_rxchan_prepare()函數(shù)來遞交接收請(qǐng)求。alt_dma_rxchan_prepare()函數(shù)原型為: typedef void (alt_rxchan_done)(void* handle, void* data);

46、int alt_dma_rxchan_prepare (alt_dma_rxchan dma, void* data, alt_u32 length, alt_rxchan_done* done, void* handle); void* handle); 調(diào)用該函數(shù)向dma通道遞交一個(gè)接收請(qǐng)求, 長度為length比特的數(shù)據(jù)要被放到data指向的 地址。該函數(shù)在DMA傳輸結(jié)束前返回。返回值指示請(qǐng)求是否被排入隊(duì)列。一個(gè)負(fù)的返回值 表示請(qǐng)求失敗。當(dāng)傳輸結(jié)束,用戶指定的函數(shù)done被調(diào)用,變量handle提供通知和接收數(shù)據(jù) 的指針。兩個(gè)附加的函數(shù)被提供來操控DMA接收通道:alt_dma_rxch

47、an_depth()和 alt_dma_rxchan_ioctl()。 如果用戶使用Altera Avalon DMA設(shè)備來從硬件(非存儲(chǔ)器之間的傳輸)接收數(shù)據(jù),調(diào) 用alt_dma_rxchan_ioctl()函數(shù),請(qǐng)求變量設(shè)成ALT_DMA_RX_ONLY_ON。具體使用細(xì)節(jié)參 看Nios II Software Developers Handbook的HAL API 部分的alt_dma_rxchan_ioctl()章節(jié)。 alt_dma_rxchan_depth()返回設(shè)備可允許的最大的接收請(qǐng)求數(shù)。alt_dma_rxchan_ioctl()執(zhí)行接 收設(shè)備中設(shè)備相關(guān)的操縱。詳細(xì)信息參考

48、HAL API章節(jié)。 下面的代碼演示的一個(gè)完整的是遞交DMA接收請(qǐng)求以及main()中的直到傳輸完成的程 序例子。 例子:接收通道的DMA傳輸 #include #include #include #include “sys/alt_dma.h” #include “alt_types.h” /* flag used to indicate the transaction is complete */ volatile int dma_complete = 0; /* function that is called when the transaction completes */ void

49、dma_done (void* handle, void* data) dma_complete = 1; int main (void) alt_u8 buffer1024; alt_dma_rxchan rx; /* Obtain a handle for the device */ if (rx = alt_dma_rxchan_open (“/dev/dma_0”) = NULL) printf (“Error: failed to open devicen”); exit (1); else /* Post the receive request */ if (alt_dma_rxc

50、han_prepare (rx, buffer, 1024, dma_done, NULL) 0) printf (“Error: failed to post receive requestn”); exit (1); /* Wait for the transaction to complete */ while (!dma_complete); printf (“Transaction completen”); alt_dma_rxchan_close (rx); return 0; 存儲(chǔ)器到存儲(chǔ)器的DMA傳輸 從一個(gè)存儲(chǔ)器緩沖器拷貝數(shù)據(jù)到另一個(gè)緩沖器,同時(shí)包括接收和發(fā)送DMA驅(qū)動(dòng)程序。

51、下面的代碼演示的是請(qǐng)求隊(duì)列中,一個(gè)接收請(qǐng)求后面跟著一個(gè)發(fā)送請(qǐng)求的過程。 例:存儲(chǔ)器之間拷貝數(shù)據(jù) #include #include #include sys/alt_dma.h #include system.h static volatile int rx_done = 0; /* * Callback function that obtains notification that the data has * been received. */ static void done (void* handle, void* data) rx_done+; /* * */ int main (i

52、nt argc, char* argv, char* envp) int rc; alt_dma_txchan txchan; alt_dma_rxchan rxchan; void* tx_data = (void*) 0x901000; /* pointer to data to send */ void* rx_buffer = (void*) 0x902000; /* pointer to rx buffer */ /* Create the transmit channel */ if (txchan = alt_dma_txchan_open(/dev/dma_0) = NULL)

53、 printf (Failed to open transmit channeln); exit (1); /* Create the receive channel */ if (rxchan = alt_dma_rxchan_open(/dev/dma_0) = NULL) printf (Failed to open receive channeln); exit (1); /* Post the transmit request */ if (rc = alt_dma_txchan_send (txchan, tx_data, 128, NULL, NULL) 0) printf (Failed to post transmit request, reason = %in, rc); exit (1); /* Post the receive request */ if (rc = alt

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論