完整的SOPC开发流程体验
课程目标:学习并掌握完整的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工程转换成自己开发可以使用的工程。