文章目录
- 实验目的
- 实验内容
- 知识需求
- 实现的原理
- hps_0.h理解头文件
- C程序编写
- 下载sof文件到开发板
- 启动DE1-SoC中的Linux系统执行例程
实验目的
这个实验是为了学习HPS(ARM)如何和FPGA进行交互。
实验内容
演示 HPS(ARM)如何控制FPGA端的LED。(FPGA端的LED作为外设,从而实现HPS控制外设)
知识需求
本实验主要分为硬件设计和软件设计两部分。Quartus硬件设计和C程序设计)
HPS和FPGA协议通信主要通过AXI包括高速总线 HPS-to-FPGA AXI、FPGA-to-HPS AXI以及Light-weight HPS-to-FPGA AXI。
当HPS作为主端(master)它可以访问FPGA端Avalon MM slave接口的所有组件,HPS作为主端AXI-Bridge包括:
- HPS-to-FPGA AXI
- Light-weight HPS-to-FPGA AXI
FPGA作为主端AXI-Bridge包括:
- FPGA-to-HPS AXI 本实验采用 HPS-to-FPGA AXI 来实现HPS控制FPGA端的LED
实现的原理
下面描述一下如何基于下面的内容ARM(HPS)的Linux应用程序 来控制FPGA端的PIO另外,控制器是连接的HPS lw h2f 因此,它可以在总线上获得HPS物理地址空间在总线。基于这个物理地址空间,我们可以使用它Linux内核内存映射设备(memory-mapped device)驱动访问PIO控制器寄存器可以控制LED的行为。采用应用程序DS-5编写编译。
hps_0.h理解头文件
在软件实验二中,已经解释了如何生成hps_0.h头文件。头文件有什么用?
该文件包含在该文件中 qsys配置一些信息。 例如: 包含了PIO控制器在Qsys相对于中分配lwh2fAXI的基地址 它表现为宏定义PIO_LED_BASE PIO控制器位宽信息表示宏定义PIO_LED_DATA_WIDTH 驱动访问寄存器时使用这两个参数
#define PIO_LED_BASE 0x0 #define PIO_LED_DATA_WIDTH 10
C程序编写
打开SOCEDS,输入elcipse&,跳转打开DS-5软件,软件中新建C项目并在项目中建立source文件。
编写如下C程序,并进行全编译,未出现错误,即可得到可执行文件。
具体步骤与实验相同。
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #define soc_cv_av #include "hwlib.h" #include "socal/socal.h" #include "socal/hps.h" #include "socal/alt_gpio.h" #include "hps_0.h" #define HW_REGS_BASE ( ALT_STM_OFST ) #define HW_REGS_SPAN ( 0x04000000 ) #define HW_REGS_MASK ( HW_REGS_SPAN - 1 )
int main() {
void *virtual_base;
int fd;
int loop_count;
int led_direction;
int led_mask;
void *h2p_lw_led_addr;
// map the address space for the LED registers into user space so we can interact with them.
// we'll actually map in the entire CSR span of the HPS since we want to access various registers within that span
//打开内存映射设备
if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) {
printf( "ERROR: could not open \"/dev/mem\"...\n" );
return( 1 );
}
//将寄存器物理地址空间映射到用户空间
virtual_base = mmap( NULL, HW_REGS_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, HW_REGS_BASE );
if( virtual_base == MAP_FAILED ) {
printf( "ERROR: mmap() failed...\n" );
close( fd );
return( 1 );
}
//PIO的虚拟地址被定义为空指针h2p_lw_led_addr,后可用该指针变量访问PIO控制器的寄存器
h2p_lw_led_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_LED_BASE ) & ( unsigned long)( HW_REGS_MASK ) );
// toggle the LEDs a bit
//流水灯的切换
loop_count = 0; //初始化,并循环60次
led_mask = 0x01;
led_direction = 0; // 0: left to right direction
while( loop_count < 60 ) {
// control led, add ~ because the led is low-active
//led灯低电平有效,因此加~
*(uint32_t *)h2p_lw_led_addr = ~led_mask;
// 把进程挂起一段时间 wait 100ms
usleep( 100*1000 );
// update led mask
if (led_direction == 0){
led_mask <<= 1;
if (led_mask == (0x01 << (PIO_LED_DATA_WIDTH-1)))
led_direction = 1; //从右到左
}else{
led_mask >>= 1;
if (led_mask == 0x01){
led_direction = 0; //从左到右
loop_count++;
}
}
} // while
// clean up our memory mapping and exit
if (munmap(virtual_base, HW_REGS_SPAN) != 0) {
printf("ERROR: munmap() failed...\n");
close(fd);
return(1);
}
close( fd );
return( 0 );
}
my_hps_led为生成的可执行文件,将其右键复制到SD卡中即可。
下载sof文件到开发板
由于此LED灯采用的是开发板FPGA部分的LED灯,因此我们需要将硬件设计的工程全编译,得到sof文件,将sof文件下载到开发板中。
启动DE1-SoC中的Linux系统执行例程
打开putty以root用户登录终端 找到我们复制到SD卡中的文件,my_hps_led,并将该可执行程序复制到根目录 采用命令修改可执行文件的权限
chmod 777 my_hps_led
采用命令运行 可执行文件
./my_hps_led
此时即可看到开发板上的LED灯做60次的流水灯操作。
总结: 本实验分为两个大的部分,硬件设计和软件设计。
- 硬件设计:采用quartus中的qsys来搭建硬件系统,将我们所需要的led组件配置进来,并将其例化到顶层中,全编译即可生成sof文件,以及sopcinfo文件。 sof文件需要将其下载到开发板 sopcinfo文件用来根据sh文件生成hps_0.h头文件
- 软件设计:采用DS-5软件来编写C程序,重点包括了LED的控制方式,以及通过硬件文件生成的hps_0.h头文件,全编译生成可执行文件,并将其放到SD卡。
最终我们将quartus生成的sof文件下载到开发板,采用串口终端调试软件putty 以实现在开发板上运行Linux系统,并通过命令找到我们所需要的可执行文件,修改权限并执行,至此,即可在开发板上看到实验效果。