SoC学习篇—外设IP使用 PIO_LED 点灯

一、添加LED外设

有关镜像烧录制作设备树等操作,可参考博文:

SOC学习篇—实现hello FPGA打印

1、添加外设

打开黄金参考工程
在这里插入图片描述
打开【platform designer】
方式一:小图标
在这里插入图片描述
方式二:【Tools】—>【Platform Designer】
在这里插入图片描述
进入【PIO】添加界面【LED外设为PIO】
在这里插入图片描述
选择【file】—>【open…】
在这里插入图片描述
打开【soc_system.qsys】文件
在这里插入图片描述
设计界面简识
在这里插入图片描述
搜索【PIO】
在这里插入图片描述
LED配置,配置完成,点击【finish】
在这里插入图片描述
进入设计界面,添加端口连线
方式一:直接连接
在这里插入图片描述
方式二:鼠标右键按图示选择【推荐使用这种方式,信号比较好查找】
在这里插入图片描述
修改输出端口名
在这里插入图片描述
基地址分配【新的设备进入,需要重新分配基地址】
在这里插入图片描述
配置完成,可以看到下面信息【无警告、报错】
在这里插入图片描述
生成新的【qsys】文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看新的【hps】接口
在这里插入图片描述
如示,【Ctrl+C】复制外设端口
在这里插入图片描述
点击【Finish】,在工程顶层例化外设LED端口【信号名同上用大写,方便引脚约束】
在这里插入图片描述
端口例化
在这里插入图片描述
点击全编译
在这里插入图片描述
引脚约束
在这里插入图片描述
可以看到引脚约束成功。至此,外设添加环节就完成了。

2、设备树和镜像烧录

设备树
打开shell,进入黄金工程所在目录,使用指令生成设备树
在这里插入图片描述
编译完成;生成设备树文件
在这里插入图片描述
进入同级目录的【output_files】,运行脚本生成【.rbf】文件
在这里插入图片描述

只需将生成的文件和镜像文件替换即可。

将生成的【.dtb】和【.rbf】文件拷到SD卡
在这里插入图片描述
将SD卡拔出,插入到开发板卡槽。
至此,硬件设计部分完成。

二、点灯C程序

1、生成新的hps头文件

shell运行指令【可使用TAB键补全】

 ./generate_hps_qsys_header.sh

在这里插入图片描述
生成文件
在这里插入图片描述

2、环境设置

使用指令进入eclipse,创建工程

详细步骤参考:SOC学习篇—实现hello FPGA打印

在这里插入图片描述
将生成的hps头文件复制到工程目录下
在这里插入图片描述
添加cv头文件
选中工程鼠标右键,选择属性
在这里插入图片描述
按提示选择
在这里插入图片描述
添加文件;选择【Add】—>【File System…】
在这里插入图片描述
找到安装路径的此两个文件
在这里插入图片描述
添加完成后如示
在这里插入图片描述

3、程序设计

导入相关库文件

//GCC标准头文件
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
//HPS厂家提供的底层定义头文件
#define soc_cv_av
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
//同用户具体的HPS应用系统相关硬件描述头文件
#include"hps_0.h"
#define HW_REGS_BASE (ALT_STM_OFST)  //HPS外设地址段基地址
#define HW_REGS_SPAN (0x04000000)  //HPS外设地址段地址空间 64MB
#define HW_REGS_MASK (HW_REGS_SPAN - 1)  //HPS外设地址段地址掩码

完整程序

//GCC标准头文件
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
//HPS厂家提供的底层定义头文件
#define soc_cv_av
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
//同用户具体的HPS应用系统相关硬件描述头文件
#include"hps_0.h"
#define HW_REGS_BASE (ALT_STM_OFST)  //HPS外设地址段基地址
#define HW_REGS_SPAN (0x04000000)  //HPS外设地址段地址空间 64MB
#define HW_REGS_MASK (HW_REGS_SPAN - 1)  //HPS外设地址段地址掩码
//led接口定义
typedef struct{
	unsigned int data;
	unsigned int dir;
}led_def;
led_def *my_led;
int led_init(void *virtual_base)
{
	void *led_addr;
	//计算led地址=虚拟地址+led偏移地址
	led_addr = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + LED_PIO_BASE) & (unsigned long)(HW_REGS_MASK));
	//将地址映射到接口(结构体指针访问地址)
	my_led = (led_def*)led_addr;
	//初始化led
	my_led->data = 0x0;
	my_led->dir  = 0x0000000f;
	return 0;
}
int main()
{
	int fd;
	void *virtual_base;
	//打开MMU
	fd = open("/dev/mem",( O_RDWR | O_SYNC ));
	//获取虚拟地址(将外设地址映射到用户空间)
	virtual_base = mmap(NULL,HW_REGS_SPAN,( PROT_READ | PROT_WRITE),MAP_SHARED,fd,HW_REGS_BASE);
	//操作外设
	led_init(virtual_base);
	while(1)
	{
		//闪烁灯
		my_led->data = 0x0000000f;//0000 1111
		sleep(1);
		my_led->data = 0x00000000;//0000 0000
		sleep(1);
	}
	//取消地址映射
	if(munmap(virtual_base,HW_REGS_SPAN) != 0)
	{
		printf("ERROR:munmap()failed...\n");
		close(fd);
		return 1;
	}
	led_init(virtual_base);
	//关闭MMU
	close(fd);
	return 0;
}

4、编译调试

编译程序,生成二进制文件
在这里插入图片描述
将此文件复制到根目录的【opt】目录下
在这里插入图片描述
开始调试
在这里插入图片描述
结果展示
在这里插入图片描述

三、按键点灯

添加按键,具体操作流程同上。
c程序实现代码

//GCC标准头文件
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
//HPS厂家提供的底层定义头文件
#define soc_cv_av
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
//同用户具体的HPS应用系统相关硬件描述头文件
#include"hps_0.h"
#define HW_REGS_BASE (ALT_STM_OFST)  //HPS外设地址段基地址
#define HW_REGS_SPAN (0x04000000)  //HPS外设地址段地址空间 64MB
#define HW_REGS_MASK (HW_REGS_SPAN - 1)  //HPS外设地址段地址掩码
//led接口定义
typedef struct{
	unsigned int data;
	unsigned int dir;
}led_def;
typedef struct{
	unsigned int data1;//按键数量
	unsigned int dir1;//按键输入
}key_def;
led_def *my_led;
key_def *my_key;
int led_init(void *virtual_base)
{
	void *led_addr;
	void *key_addr;
	//计算led地址=虚拟地址+led偏移地址
	led_addr = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + LED_PIO_BASE) & (unsigned long)(HW_REGS_MASK));
	//计算key地址
	key_addr = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + KEY_PIO_BASE) & (unsigned long)(HW_REGS_MASK));
	//将地址映射到接口(结构体指针访问地址)
	my_led = (led_def*)led_addr;
	my_key = (key_def*)key_addr;
	//初始化led
	my_led->data = 0x0;
	my_led->dir  = 0x0000000f;
	//初始化key
	//my_key->data1 = 0x0;//按键不赋值
	my_key->dir1  = 0x000;//input
	return 0;
}
int main()
{
	int fd;
	int a[8] = {1,2,4,8,16,32,64,128};
	int b[4] = {2,10,42,170};
	void *virtual_base;
	int i;
	//打开MMU
	fd = open("/dev/mem",( O_RDWR | O_SYNC ));
	//获取虚拟地址(将外设地址映射到用户空间)
	virtual_base = mmap(NULL,HW_REGS_SPAN,( PROT_READ | PROT_WRITE),MAP_SHARED,fd,HW_REGS_BASE);
	//操作外设
	led_init(virtual_base);
	while(1)
	{
		if((my_key->data1 & 1)==0)
		{
			//按键1控制  流水灯
			for(i=0;i<8;i++)
			{
				my_led->data = a[i];
				sleep(1);
			}
		}
		else if(((my_key->data1>>1) & 1) == 0)
		{
			//按键2控制 呼吸灯
			for(i=0;i<500;i++)
			{
				my_led->data = 0xff;
				usleep(10*i);
				my_led->data = 0x00000000;
				usleep(5000-10*i);
			}
		}
		else if(((my_key->data1>>2) & 1) == 0)
		{
			//按键3控制 错位灯
			for(i=0;i<4;i++)
			{
				my_led->data = b[i];
				sleep(1);
			}
		}
		else
		{
			//没有按键 交错闪烁
			my_led->data = 0x0000000f;//0000 1111
			sleep(1);
			my_led->data = 0x000000f0;//1111 0000
			sleep(2);
			my_led->data = 0x00000000;//0000 0000
			sleep(1);
		}
	}
	//取消地址映射
	if(munmap(virtual_base,HW_REGS_SPAN) != 0)
	{
		printf("ERROR:munmap()failed...\n");
		close(fd);
		return 1;
	}
	led_init(virtual_base);
	//关闭MMU
	close(fd);
	return 0;
}

流水灯展示
在这里插入图片描述

版权声明:本文为CSDN博主「小小怪༻」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/QWERTYzxw/article/details/121789244

生成海报
点赞 0

小小怪༻

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

FPAG学习笔记——I2C接口实现

一、I2C总线介绍 I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。 主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址

FPGA实战(五)时钟IP核(MMCM PLL)

来自正点原子的学习笔记 (关于开发板资源的相关理论我不太懂) (本文侧重于简单的理解和应用层面) 1时钟资源简介 时钟资源主要是对输入的时钟进行倍频、分频、调整相位。 全局时钟是一种专