SOPC的課程已經結束了,短短4天,要消化的內容還真不少。今天又開始了DDR2 SDRAM的課程,其實在我來北京之前他們已經開始SDRAM的課程了,想起我做SDRAM的時候,真的是好費勁,又沒人指點,代碼寫了一大串,前仿真也做的差不多,后仿就不行了,有些東西不知道怎么解決,還涉及到時序約束這門聽起來高大上的知識,所以那段時間把我糾結的不輕。看樣子在我離開北京之前這邊應該是一直講SDRAM了,上課的是李凡老師,一個很和藹,很低調的老師,據說已經做了三四十年的工程師了,也是國內頂尖的人物了。打算這幾天好好再學一下SDRAM,畢竟這東西用處很廣,前景也很明朗,估計消化掉SOPC的內容后就要再開始SDRAM的征程了,這樣在北京的20天也就不虛此行了~ 今天我們講定時器中斷與串行口中斷,相信學過單片的朋友都用過這東西,對這東西也并不陌生,其實無非就是我們以前是對單片機編程,今天是對我們上次自己搭建的那個硬件系統進行編程,即我們的NIOS II 處理器。 和上個實驗一樣,小墨同學先來跟大家學文檔,從文檔入手,做到每一條代碼都有根有據吧,這次還是要用到這個文檔 n2cpu_nii5v3,我會附在文章后面等會,供大家下載 我們先來看定時器這個核 學IP核總要先知道這個核是干什么的吧,這里就和大家一起來啃啃英文,有一點還是提醒大家,文檔還是要看原版,即使你的英文不怎么好,也要試著去看,慢慢的就好了,我一般是喜歡開著有道詞典一般看英文,遇到沒見過的詞鼠標一點就出來了,個人感覺比較方便,大家也可以試一下 我們先來總體看一下這個核,上面一段英文是說呢, 1、這個定時器核可以配置成32位或者64位的定時器,這個我們在SOPC builder里面已經配置好了 2、可以控制定時器的開始,停止與復位 3、有兩種計數模式,一種是計數一次就停止,一種是持續計數。其實我們的定時器是先讓我們設定一個初值給它,然后定時器從這個初值開始遞減,第一種計數模式就是定時器從初值遞減到0時就停止計數了,第二種模式呢就是仍然繼續計數 4、第四行就告訴了我們這個計數器的計數方式,即遞減式計數 5、然后后面那幾行呢大概就是說有幾種操作選項,例如我們可以開始或者關閉定時器中斷啊,開啟看門狗定時器啊,當定時器計滿一次數的時候發出一個高脈沖信號啊之類的 大概就是這些內容了吧~ 然后我們可以去看一下它的功能描述框圖這一頁,加深一些理解 大概意思就是說,這個定時器核里包含了這么多寄存器,什么狀態寄存器,控制寄存器之類的,當我們開啟寄存器的時候,count里會自動載入我們設定的初值,開始計數,當計滿一次的時候會產生一個中斷給CPU,知道大體意思就行,具體的到后面寄存器視圖再仔細看他們的具體功能 下面我們需要看一下它的software files這一頁,知道要用到哪些頭文件 重點來了,我們主要的任務就是看這個定時器核的寄存器映射視圖,這也就直接關系到我們代碼的編寫 上面一段話大體意思是說啊,我們如果使用了硬件抽象層系統庫提供給NIOS II處理器的這樣一個標準配置的話,我們就沒必要去訪問定時器這個核的寄存器了,一般來說這個寄存器映射圖是準們給我們編寫器件驅動用的 前面一段話我理解的不是很好,不敢在這里忽悠大家,但是我們的目的就是編寫器件驅動嘛,所以我們還是可以使用的 下面就可以看到這個核為我們提供的幾組寄存器了,大體瀏覽一下,主要是看下面的功能介紹 先來看這兩個寄存器 狀態寄存器的第零位呢是TO位,TO從字面上理解就是timeout,即時間溢出嘛,就是說當我們計數器計到0 的時候TO位會自動被置1,如果我們想要置0的話需要在狀態寄存器里手動清0,這也就解釋了為什么我們后面的代碼每次進入中斷以后為什么要清TO位了 RUN寄存器可以通過上面的解釋大概說,RUN寄存器是用來指示定時器當前狀態的一個數據位,即當寄存器工作的時候他被設置為1,否則設置為0 ,而且這一位不受你往狀態寄存器寫數據的影響。 控制寄存器呢大概就是開啟關閉中斷,開始計數或者停止計數之類的,大家可以自己消化英文,下面的period_n寄存器無非就是我們設置一個初值給它,大家也可以自己看 好了,需要看的也就這些了,下面就是我們根據我們從文檔中獲得的知識去編寫我們的代碼了 首先就是定義頭文件么 system.h即我們硬件系統生成時產生的,里面定義了我們各種模塊的基址啊,位寬啊之類的,下面就是我們要操作的七段數碼管的基址及相關信息,,有了基址我們才能訪問到數碼所在的PIO,才能給他賦相應的值 其他那些頭文件無非就是定時器核的寄存器頭文件和數據類型頭文件,還有IO操作的的一些函數的頭文件 代碼部分其實很簡單,先是設置定時器中斷,每進入一次中斷將TO位清零,這里用到IOWR這個函數就是IO頭文件里面定義的一個函數之一,用來對狀態寄存器進行寫數據,然后就是數據自加1,由于我們在sopc builder里面設置的時候設置的定時器定時單位是ms,所以我們計數1000次也就是1S了 主函數部分就是上來調用函數對數碼管的位選和片選端初始化,將定時器中斷打開,這些都沒什么,要注意一點就是中斷函數的注冊,即 alt_irq_register(TIMER_IRQ,TIMER_BASE,handle_Timer0_interrupts); 就是我們給我的定時器一個定義,即我們要訪問的定時器的基址,和要命名的名字,只有注冊了中斷,我們才能進入中斷函數 好了,我們可以暫時跳過調試這一環節,因為工程比較簡單,我們可以直接下板 在下板的過程中大家可能會遇到這樣下載失敗的情況 No Nios II target connection paths were located. Check connections and that a Nios II .sof is downloaded. 注意要按順序來做,一般是先下載硬件配置文件.SOF,再對軟件進行全編譯,然后再下載一般就可以解決了 下面我們再來看UART這個核 先來總體來看一下這個核,大體上是說啊,這個UART核可以通過Avalon總線,作為Avalon總線的一個從機,來實現FPGA與外圍器件之間的通信,這個核服從RS232時序協議,提供了可手動配置的波特率啊,奇偶校驗位啊,停止位啊之類的數據位,控制數據流向啊,允許設計者調用系統給出的必要的一些函數啊之類的 再大體看一下功能框圖 和之前的差不多,核的內部也是一系列寄存器,時鐘進來之后進入divisor ,進行波特率的配置,然后通過控制寄存器啊,狀態寄存器啊控制數據的讀寫功能,大體上是這個意思,具體還要看后面的寄存器映射視圖 太過詳細的東西這里不做介紹,留給大家慢慢消化,主要是來看一下它的寄存器映射視圖 這里有6組寄存器,包括什么讀寫寄存器,控制寄存器,狀態寄存器,波特率設置寄存器之類的,具體功能大同小異,簡單來看一下 先來看一下讀寄存器吧 大體上是說啊,這個讀寄存器可以保存住來自RXD口輸入過來的數據,當一個新的字符完全進入這個寄存器之后啊,那么狀態寄存器的rrdy位將會自動置1,當讀寄存器中的數據被讀出的時候,rrdy位自動置0,如果當讀寄存器中的數值還沒有被讀完,又有新字符輸入的話,那么就會發生錯誤,狀態寄存器的的roe位自動置1,新的數據將會覆蓋原有的數據,對讀寄存器寫數據是沒有影響的,大體上就是這個意思了 狀態寄存器位數太多,這里就不一一講解,大體上是說,當發生各種錯誤,例如什么奇偶校驗位錯誤,停止位錯誤之類的,接收發送錯誤之類的,還有指示讀寫寄存器狀態的,當有數據的時候置1,空的時候置0之類的,大家還是自己去理解 控制寄存器主要是控制中斷,包括這種中斷,這里我們只需要用到發送中斷和接收中斷,其他的大家可以自己看一下 代碼部分呢主先來看一下初始化部分 由于我們設置的NIOS II處理器是32位的,因此我們的寄存器偏移地址根據基址也就知道了,即32/8 = 4, 先對控制寄存器操作,打開就收發送使能端,control寄存器是第5個寄存器,偏移為12 IOWR_16DIRECT(UART_BASE,12,0xc0); 狀態寄存器清零,狀態寄存器偏移為8 IOWR_16DIRECT(UART_BASE,8, 0x0); 注冊中斷函數 alt_irq_register(UART_IRQ,UART_BASE,Uart_rx_ISR); 接收中斷部分主要就是將狀態寄存器的數值讀回,判斷狀態寄存器的rrdy位的狀態,如果是1的話那么表明數據接收完畢,可以讀了,然后將數據保存起來,將接收數據位置1表明我們已經收到數據了 以后小墨同學的教程會跟這款開發板配套,想跟小墨同學一起學習,一起進步的的可以考慮一下購買一塊開發板,畢竟學習要舍得投資嘛 |