文章目录[隐藏]
一、添加LED外设
有关镜像烧录制作设备树等操作,可参考博文:
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
暂无评论