FPGA 之 SOPC 系列(六)Nios II 程序开发 II
FPGA 之 SOPC 系列(六)Nios II 程序開發 II
今天給大俠帶來今天帶來FPGA 之 SOPC 系列第六篇,Nios II 程序開發 II,希望對各位大俠的學習有參考價值,話不多說,上貨。
本篇接著第五篇繼續介紹NIOS II的寄存器級編程方式,以該方式的定時器的編程實例應用。
以下為本篇的目錄簡介:
-
6.1 項目文件的管理
-
6.2 寄存器級編程
-
6.3 定時器應用
?
6.1 項目文件的管理
每個C工程中,可以以功能為依據對源文件迕行文件夾分類。文件夾不可以出現空格、除英文字母、數字、下劃線外的字符;更不允許出現漢字等非 ASCII碼字符。例如某個工程可以劃分為如下文件夾:
-
doc 說明文檔
-
config 系統相關配置文件夾(系統參數配置、編譯器、連接器配置文件等)
-
driver 硬件驅動文件夾(包括芯片驅動、cpu外設驅動等)
-
font 字體驅動
-
Gui 圖形界面驅動
-
main 主程序
-
include 頭文件
-
obj 編譯后的目標文件
功能劃分應以邏輯清晰、層次關系明顯為目的。一旦劃分好后,不可越級調用系統資源(例如只有driver內文件內直接操作硬件資源,其他文件夾代碼均不可調用最底層硬件資源)。也不要互相調用而使系統資源很快耗盡
文件一旦建立,就需在文件頭說明文件目的、版權及歷史記錄,每次修改后必須記錄。工程完工或者是間歇性擱置時,需要對所有工程文件夾、文件進行只讀屬性設置及當前狀態設置。對源代碼最好做到每天一備份,以防意外篡改及丟失,以備恢復之用。
?
6.2 寄存器級編程
例:點亮LED的例子轉換新的編程方式
第一步,按照上述的文件管理方式,建立一個放置頭文件的文件夾,命名為inc, 在工程文件夾上點擊右鍵,然后點擊NEW中的SOURCE FOLDER。
下一步,在紅圈處輸入inc,點擊finish,完成文件夾建立。
下一步,在這個新建的文件夾下建立一個頭文件,方法如下圖所示,在inc上點擊右鍵,然后點擊NEW中的header file,輸入sopc.h。
打開剛才建立的頭文件,補充完代碼后如下:
#ifndef SOPC_H_ #define SOPC_H_ #include "system.h" #define _LED typedef struct { unsigned long int DATA; unsigned long int DIRECTION; unsigned long int INTERRUPT_MASK;; unsigned long int EDGE_CAPTURE; }PIO_STR; #ifdef _LED #define LED ((PIO_STR *)LED_PIO_BASE) #endif #endif /*SOPC_H_*/
其中定義了一個結構體,這個結構體被指向了LED_PIO_BASE,查相關手冊, n2cpu_Embedded Peripherals.pdf。
這兩個表格就是PIOCORE寄存器映射,我們這個結構體啊就是根據它寫出來的,名字不重要,重要的是順序,也就是偏移量。第一項是數據DATA,第二項是IO口方向,第三項是中斷控制位,第四項是邊沿控制位。他們每一項都有N位,這個N就是我們在軟件構建中的寬度,這個時候我們這里的N等于幾?
-
#define LED ((PIO_STR *)LED_PIO_BASE)
-
它就是怎么把我們定義的結構體給勾上LED設備的。記得LED_PIO_BASE,它就是我們在SYSTEM.H中特別強調的。定義了一個宏,命名為LED,它是指向LED_PIO_BASE的結構指針,這個結構就是PIO_STR.
-
#define _LED
-
#ifdef _LED
-
#endif
-
意思是為了控制定義#define LED ((PIO_STR *)LED_PIO_BASE)的,這樣做是為了增強代碼的嚴謹性和可控制性。
把之前的模板文件hello_world.c名字改為main.c并將它放到main文件夾中,右擊rename后,選中main.c右擊鼠標move后,選中main文件夾就ok了。
#include <stdio.h> #include <unistd.h> #include "../inc/sopc.h" int main (void) __attribute__ ((weak, alias ("alt_main"))); int alt_main() { int i; while (1) { for(i=0;i<4;i++){ LED->DATA =1<<i; usleep(500000); } } return 0; }
LED->DATA =1<<i;LED是在SOPC.H中定義的宏,是結構體指針,它的結構體中DATA的內容(不是地址)。這里的usleep是微秒級延時的。
總結一下:
-
文檔的歸類管理。
-
Sopc.h定義來源是相關外設的文檔寄存器。
-
操作定義好的外設結構體變量編程。
并不是,要看什么要的外設,想FLASH這種外設,采用這種方式的話,累死你,我們就直接可以使用API來寫就行了。這種方式對我們了解nios的本質是很有幫助的。
?
6.3 定時器應用
概覽
該時間計數器是一個為諸如NIOS II 等基于Avalon架構的處理器設計的時間計數器。該計數器有如下特點:
(1)32位和64位計數;
(2)具有計數開始、計數停止、和復位計數器功能;
(3)兩種技術模式:單次計數、連續計數;
(4)計數周期寄存器;
(5)當計數器計數到0時,可以選擇使能或者禁止觸發中斷(IRQ);
(6)可選作為看門狗,產生系統復位;
(7)可選產生周期脈沖,當計數器計數到0時;
(8)可用于32位或者16位處理器中。如16位的NIOS和32位的NIOS II。
Interval TimerCore 功能描述
(1)Avalon-MM提供可對6個16位寄存器操作的功能;
(2)可選周期脈沖輸出。
所有的寄存器都是16位寬度的,因此可適應于16位或者32位處理器。若該核被配置為一個固定的周期,那么,周期寄存器就不存在。
計數周期(Timeout Period)
計數周期決定了周期計數器值。當使能可寫周期(Writeableperiod),處理器可以通過寫周期計數器( period registers)改變計數器值?;蛘弋斀箍蓪懼芷?#xff08;Writeableperiod),周期計數器(period registers)不可經過處理器的寫操作而改變;此時周期計數器只能是一個不可改變的固定周期計數值。Interval Timer Core的計數周期是系統時鐘周期的整數倍。實際的時鐘周期讀者可以這樣求。
(1)求出系統的時鐘。指驅動Interval Timer Core的時鐘。一般與NIOS II 時鐘一致。
(2)將周期計數器里面高16位和低16位的值乘與時鐘時期即得計數周期。
計數大小(Counter Size)
該設定決定了計數器的位寬??梢栽O定為32位或者64位。32位位寬的計數器包含有2個16位的寄存器;而64位位寬的計數器包含有4個16位寬的寄存器。該設定同樣應用至snap單元。
硬件選項
(1)Simple periodic interrupt—該設定用于只需要一個帶有中斷(IRQ)的計數器。該方式下,計數周期是固定不可軟件更改的,且計數不能停止但中斷(IRQ)可禁止。
(2)Full-featured—該配置適用于一個可被處理器更改,可變計數周期,且其開始、停止均可被更改的計數器。
(3)Watchdog—適用于系統需要看門狗的情況。當系統停止響應,該配置能使系統復位。
寄存器(registeregister)設定說明
(1)Writeable period——當選中此項,則主外設(NIOS II)可通過寫周期寄存器(period registers)達到修改計數周期的目的。若未選中此項,則計數周期被確定為(Timeout Period),不可更改;同時周期寄存器(period registers)不再存在。
(2)Readable snapshot——當選中此項,則主外設(NIOS II )可以讀取當前計數值。若未選中此項,則主外設只能依靠查詢狀態寄存器(status register)或者中斷(IRQ)標志來得知計數狀態;此時(snap registers)并不存在,讀取該寄存器會有不確定的數值。
(3)Start/Stop control bits——當選中此項,則主外設( NIOS II )可以通過寫控制寄存器(control register)來啟動、停止計數器。若未選中此項,則計數器默認為連續計數模式。值得注意的是,當系統看門狗復位(System reset on timeout (watchdog))是使能狀態,則控制寄存器(control register)中的(start)位被置位,而不管Start/Stop 控制位的狀態。
信號輸出選項
( 1 ) Timeout pulse (1 clock wide) — — 當選中該項, 則計數器產生一個信號端口(timeout_pulse),該信號端口在計數器減計數至0時產生一個系統時鐘周期的高電平。若未選中該項,則計數器不產生該信號端口。
(2)System reset on timeout (watchdog)——當選中該項,則計數器產生一個復位信號端口(resetrequest port)該信號在計數器減計數至0時產生一個系統時鐘周期的高電平。若未選中該項,則該信號端口不存在。
配置計數器為看門狗
若要使用看門狗,則應作如下選擇。
(1)presets:選擇Watchdog;
(2)Timeout Period修改成所需要的時間
(3)Writeable period禁止;
(4)Readable snapshot禁止;
(5)Start/Stop control bits禁止;
(6)Timeout pulse禁止;
(7)System reset on timeout (watchdog)使能。
復位之后看門狗是禁止的。隨后,處理器往控制寄存器(control register)的START位寫1。開啟看門狗計數器??撮T狗一旦開啟,就不能結束。為了不使系統復位,處理器應該定時地復位計數值。
Interval Timer Core 軟件編寫
狀態寄存器(status Register Bits)
TO——當計數器減計數到0時,置1。一旦置1,則必須由主外設(NIOS II)清0;
RUN——當計數器在計數運行時,RUN=1;否則RUN=0。寫RUN對值無影響。
控制寄存器(control register)
ITO——當ITO=1時,計數器會產生中斷。反之則反。
CONT——若COUNT=1則計數器計數到0連續計數,知道STOP=1;若COUNT=0則計數器計數到0時,停止計數。
START——寫1到START則使計數器開始計數。當計數器正在計數運行,則寫START無效。
STOP——寫1到STOP則使計數器停止計數。若計數器已經停止計數,則寫STOP無效。當SOPC配置為Start/Stop control bits為關閉,則寫STOP無效。
中斷(IRQ)
當計數器減計數到0時并且控制寄存器(congtrol register)ITO位被置1,則可產生定時器中斷。
處理中斷應用以下兩種方式之一:
(1)清除狀態寄存器(status register)的TO位;
(2)清除控制寄存器(congtrol register)ITO位,禁止中斷。否則會產生不確定結果。
實例程序
/**//************************ 定時器中斷注冊初始化函數*****************************/ void InitInterrupt() { //----------------------------定時器中斷,系統時鐘66.7MHz-------------------- ------// alt_irq_register(TIMER_IRQ,NULL,Timer_interrupts); //注冊中斷函數 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_BASE, 0x000A); IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_BASE, 0x2C2A);//修改定時時間10ms IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 7); //啟動定時器允許中斷,連續計數 } /**//*************************定時器中斷服務函數*****************************/ void Timer_interrupts(void* context, alt_u32 id) { /**//***************************服務代碼**************/ /**//**********************退出時清狀態寄存器***********/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE, 0); //清狀態寄存器 } typedef struct{ union{ struct{ volatile unsigned long int TO :1; volatile unsigned long int RUN :1; volatile unsigned long int NC :30; }BITS; volatile unsigned long int WORD; }STATUS; union{ struct{ volatile unsigned long int ITO :1; volatile unsigned long int CONT :1; volatile unsigned long int START :1; volatile unsigned long int STOP : 1; volatile unsigned long int NC :28; }BITS; volatile unsigned long int WORD; }CONTROL; volatile unsigned long int PERIODL; volatile unsigned long int PERIODH; volatile unsigned long int SNAPL; volatile unsigned long int SNAPH; }TIMER;
FPGA 之 SOPC 系列第六篇就到這里結束,下一篇將帶來第七篇,NIOS II 高級技術等相關內容。
?
【QQ交流群】
群號:173560979,進群暗語:FPGA技術江湖粉絲。
多年的FPGA企業開發經驗,各種通俗易懂的學習資料以及學習方法,濃厚的交流學習氛圍,QQ群目前已有1000多名志同道合的小伙伴,無廣告純凈模式,給技術交流一片凈土,從初學小白到行業精英業界大佬等,從軍工領域到民用企業等,從通信、圖像處理到人工智能等各個方向應有盡有。
?
【微信交流群】
現微信交流群已建立08群,人數已達數千人,歡迎關注“FPGA技術江湖”微信公眾號,可獲取進群方式。
完
后續會持續更新,帶來Vivado、 ISE、Quartus II 、candence等安裝相關設計教程,學習資源、項目資源、好文推薦等,希望大俠持續關注。
江湖偌大,繼續闖蕩,愿大俠一切安好,有緣再見!
總結
以上是生活随笔為你收集整理的FPGA 之 SOPC 系列(六)Nios II 程序开发 II的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编写一个c语言程序 杨辉三角,杨辉三角
- 下一篇: delphi 获取硬盘序列号、cpu号、