課程目標:學習並掌握完整的SOPC開發流程。
開發環境:Quartus15.1
學習內容:1、使用QSYS工具建立能夠運行流水燈項目的NIOS II處理器系統
2、在quartus ii中添加NIOS II 系統文件(完成SOPC系統搭建);
3、在nios II EDS中創建NIOS ii軟件工程,實現流水燈代碼;
4、在開發板上運行流水燈程序。
設計流程:
創建一個新的project 工程
新建一個GHRD.v頂層文件
打開QSYS
選擇最新的NIOS II CPU 核
由於是第一次使用NIOS ii 的CPU 核,所以選擇默認的設置點擊finish即可
添加on-chip-ram作為CPU的運行內存
修改一下內存大小,保證內存足夠大
添加只輸出型的四位PIO
同樣,將其重命名為易觀察的名字
主要單元添加完畢后,即可進行總線類型的連接了
首先是數據總線主機與從機相連
然后是指令總線與從機存儲數據的模塊的數據總線相連
連接時鍾
創建全局復位網絡
連接完畢后的連接圖
導出PIO信號
分配基地址
此時,警告框還是有兩個錯誤,這是因為,在設置CPU時,沒有設置復位地址和異常地址,雙擊nios2_gen2_0,將vector指向指令存儲器
保存並生成.qsys文件
生成HDL文件
生成例化模板
點擊copy,將內容粘貼到之前創建的GHRD的頂層文件中
至此,系統的NIOS II處理器就搭建完成了
下面就是對SOPC系統進行完善,在quartus II 軟件中添加NIOS ii處理器系統並分配引腳
添加quartus II處理器系統QSYS文件
對頂層的GHRD文件進行編寫
module GHRD( clk50m, rst_n, led, ); input clk50m; input rst_n; output [3:0]led; cpu u0 ( .clk_clk (clk50m), // clk.clk .reset_reset_n (rst_n), // reset.reset_n .pio_led_export (led) // pio_led.export ); endmodule
編譯完成了可以對比編譯結果查看自己所用的FPGA,觀察邏輯結構是否夠用,由圖可知是夠用的。
分配引腳
編寫EDS代碼
打開后將工作空間設置到GHRD開發環境的工作空間
新建一個模板工程
led_run_bsp的板級支持包的工程結構
為了保證工程在后面可以直接調用,這里新建一個文件夾來編寫代碼
在文件夾下創建兩個文件夾啊inc(存放頭文件.h)src(存放源文件.c)
創建一個.h文件
編寫led.h代碼
#ifndef LED_H_ #define LED_H_ #include"system.h" #include"altera_avalon_pio_regs.h" #include"alt_types.h" typedef void *LED_HANDLE; typedef struct{ alt_u32 led_base; alt_u32 led_data; }CoreCourse_LED; #define LED_ALL_OFF 0xffffffff #define LED0 0x00000001 #define LED1 0x00000002 #define LED2 0x00000004 #define LED3 0x00000008 /* #define LED4 0x00000010 #define LED5 0x00000020 #define LED6 0x00000040 #define LED7 0x00000080 #define LED8 0x00000100 #define LED9 0x00000200 #define LED10 0x00000400 #define LED11 0x00000800 #define LED12 0x00001000 #define LED13 0x00002000 #define LED14 0x00004000 #define LED15 0x00008000 #define LED16 0x00010000 #define LED17 0x00020000 #define LED18 0x00040000 #define LED19 0x00080000 #define LED20 0x00100000 #define LED21 0x00200000 #define LED22 0x00400000 #define LED23 0x00800000 #define LED24 0x01000000 #define LED25 0x02000000 #define LED26 0x04000000 #define LED27 0x08000000 #define LED28 0x10000000 #define LED29 0x20000000 #define LED30 0x40000000 #define LED31 0x80000000 */ LED_HANDLE LED_Init(const alt_u32 led_base); void LED_Off(CoreCourse_LED *p, alt_u32 ledx); void LED_On(CoreCourse_LED *p, alt_u32 ledx); void LED_Toggle(CoreCourse_LED *p, alt_u32 ledx); void LED_WriteData(CoreCourse_LED *p, alt_u32 leds); #endif /* LED_H_ */
創建一個.c空文件
同樣編寫led.c代碼
#include "led.h" #include <string.h> #include <stdlib.h> /****************************************************************************** * 函數名 : LED_Init * 描述 : 初始化LED結構體並返回結構體指針地址 * 輸入 : led_base ,system.h中定義的LED的基地址 * 輸出 : 無 * Return :經過初始化的LED結構體指針 *******************************************************************************/ LED_HANDLE LED_Init(const alt_u32 led_base) { CoreCourse_LED *p; p = malloc(sizeof(CoreCourse_LED)); if (!p) return p; memset(p, 0, sizeof(CoreCourse_LED)); p->led_base = led_base; p->led_data = 0xffffffff; IOWR_ALTERA_AVALON_PIO_DATA(p->led_base, p->led_data); return p; } /****************************************************************************** * 函數名 : LED_Off * 描述 : 關閉一個或多個LED * 輸入 : p ,LED結構體指針 * :LEDx,需要關閉的LED * 輸出 : 無 * Return :無 *******************************************************************************/ void LED_Off(CoreCourse_LED *p, alt_u32 ledx) { p->led_data = p->led_data | ledx; IOWR_ALTERA_AVALON_PIO_DATA(p->led_base, p->led_data); } /****************************************************************************** * 函數名 : LED_On * 描述 : 打開一個或多個LED * 輸入 : p ,LED結構體指針 * :LEDx,需要打開的LED * 輸出 : 無 * Return :無 *******************************************************************************/ void LED_On(CoreCourse_LED *p, alt_u32 ledx) { p->led_data = p->led_data & (~ledx); IOWR_ALTERA_AVALON_PIO_DATA(p->led_base, p->led_data); } /****************************************************************************** * 函數名 : LED_Toggle * 描述 : 翻轉一個或多個LED * 輸入 : p ,LED結構體指針 * :LEDx,需要翻轉的LED * 輸出 : 無 * Return :無 *******************************************************************************/ void LED_Toggle(CoreCourse_LED *p, alt_u32 ledx) { p->led_data ^= ledx; IOWR_ALTERA_AVALON_PIO_DATA(p->led_base, p->led_data); } /****************************************************************************** * 函數名 : LEDS_WriteData * 描述 : 直接控制所有LED的狀態,輸入的LED將被點亮,未輸入的將被關閉 * 輸入 : p ,LED結構體指針 * :LEDx,需要點亮的LED * 輸出 : 無 * Return :無 *******************************************************************************/ void LED_WriteData(CoreCourse_LED *p, alt_u32 leds){ p->led_data = leds; IOWR_ALTERA_AVALON_PIO_DATA(p->led_base, p->led_data); } /* main函數中初始化示例代碼 * * LED_HANDLE hLED; hLED = LED_Init(PIO_LED_BASE); if (!hLED) { // printf("Failed to init LED\n"); } */ /* LED_WriteData()函數使用示例代碼 * *LED_WriteData(hLED, LED0 | LED2); //LED0和LED2點亮,LED1和LED3關閉 } */ /* LED_On()函數使用示例代碼 * *LED_On(hLED, LED0 | LED2); //點亮LED0和LED2 } */ /* LED_Off()函數使用示例代碼 * *LED_Off(hLED, LED1 | LED3); //熄滅LED1和LED3 }*/ /* LED_Toggle()函數使用示例代碼 * *LED_Toggle(hLED, LED3); //翻轉LED3 }*/
將helloworld.c文件更改為main.c文件,並編寫main.c
/******************************************************************** * 文 件 名:main.c * 功 能:LED顯示控制。 * 通過PIO直接控制4個LED產生亮滅效果 * 說 明: * ********************************************************************/ #include "system.h" #include "altera_avalon_pio_regs.h" #include "alt_types.h" #include "led.h" /****************************************************************************** * 函數名 : DelayNs * 描述 : 簡易延時 * 輸入 : 需要延時的數值 * 輸出 : 無 * Return :無 *******************************************************************************/ void DelayNs(alt_u32 i) { while (i--) ; } /******************************************************************** * 名 稱:main() * 功 能:使用所有LED API控制LED運行 ********************************************************************/ int main(void) { alt_u32 i; //volatile alt_u32 j; LED_HANDLE hLED; hLED = LED_Init(PIO_LED_BASE); if (!hLED) { // printf("Failed to init LED\n"); } while (1) { //測試LED_WriteData函數功能 i = 2; while (i--){ LED_WriteData(hLED, LED0 | LED2); //LED1和LED3點亮,LED0和LED2關閉 DelayNs(5000000); LED_WriteData(hLED, LED1 | LED3); //LED0和LED2點亮,LED1和LED3關閉 DelayNs(5000000); } LED_WriteData(hLED, LED_ALL_OFF); //關閉所有的LED DelayNs(10000000); //測試LED_On函數和LED_Off函數功能 i = 2; while (i--){ LED_On(hLED, LED0 | LED2); //點亮LED0和LED2 DelayNs(5000000); LED_On(hLED, LED1 | LED3); //點亮LED1和LED3 DelayNs(10000000); LED_Off(hLED, LED0 | LED2); //熄滅LED0和LED2 DelayNs(5000000); LED_Off(hLED, LED1 | LED3); //熄滅LED1和LED3 DelayNs(10000000); } LED_WriteData(hLED, LED_ALL_OFF); //關閉所有的LED //測試LED_Toggle函數功能 i = 8; while (i--){ LED_Toggle(hLED, LED3); //翻轉LED3 DelayNs(5000000); } } return 0; }
添加led_run_bsp的路徑
添加led.h的路徑
對工程進行編譯
將quartus之前生成的.sof文件燒寫到FPGA開發板中,然后在NIOS ii中選擇進行仿真運行
等待一會后會彈出如下界面,之后可以按照keil仿真的方法進行
實驗現象http://v.youku.com/v_show/id_XMjk0NDQwOTQyOA==.html?spm=a2h3j.8428770.3416059.1
本文的源代碼將在下篇文章上傳,並講解如何將別人的NIOS ii工程轉換成自己開發可以使用的工程。