《Altera De1-SoC培训教材》中的环境
[1] 培训教材.https://pan.baidu.com/s/1uFRa-5kuf9m_q_UyVIRS4A
[2] Quartus下载. https://www.altera.com.cn/downloads/download-center.html
[3] DE1-SoC Board资源.https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=Taiwan&CategoryNo=173&No=869&PartNo=4
[4] Quartus 13.1 crack. https://pan.baidu.com/s/1xKbBXYKyD2_76tdNFyC9Sg
打开”~\altera\13.1\embedded”路径下的Embedded_Command_Shell.bat文件,出现两个warning
解决方法
开发板接通电源后,有两根线可以用来de1-soc与计算机连接
使用串口终端工具putty与DE1-SOC连接。
如图保存设置后,打开开发板电源,点击putty中的open。注意串口不一定是COM3,要使用设备管理器查看
使用tool工具包中Win32DiskImager将linux镜像刻录到microSD卡(4G以上)上
将刻录了Linux的SD卡插入开发板上microSD card的插槽上,打开开发板电源。
打开putty,load de1-soc_usb,点击open。
若putty没有反应,按下enter键,若开发板启动正常,应出现用户名输入。用户名为root,密码在下载的Linux镜像文件夹中找,是readme.txt。
网络登陆脚本connect.sh
#!/bin/bash
USERID=20**********
PASSWORD=20**********
echo login
curl ‘https://connect.cuc.edu.cn/action.jsp’ –data “act=1&userid=$USERID&passwd=$PASSWORD”
注意
使用SSH安全登录开发板,用到了SSH密匙。 putty和filezilla均通过密匙登录开发板。
之后filezilla可以传输文件了。
解释
在软件实验三种用到了SOPC info file(.sopcinfo)
目标:在DE1-SoC上输出“Hello World\n”
文件:
main.c
#include
int main(int argc, char **argv)
{
printf("hello world\n");
return 0;
}
Makefile
TARGET = my_first_hps
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -g -Wall -I $(SOCEDS_DEST_ROOT)/ip/altera/hps/altera_hps/hwlib/include
LDFLAGS = -g -Wall
CC = $(CROSS_COMPILE)gcc
ARCH = arm
build: $(TARGET)
$(TARGET): main.o
$(CC) $(LDFLAGS) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -f $(TARGET) *.a *.o *~
编译运行步骤:
本实验与实验一相同,只用到DE1-SoC的HPS部分。只需在embedded command shell.bat中使用两个文件*.c和Makefile生成可执行文件,将文件传输到linux系统中并改成可执行文件,即可运行。
控制HPS的LED和KEY。运行可执行文件后,HPS的LED会先闪烁两次。之后按下HPS的KEY,LED亮起,否则熄灭。
通过linux内核memory-mapped device访问GPIO控制器。
可以通过如下软件 API 访问 GPIO 控制器的寄存器
* open: 打开内存映射设备驱动
* mmap: 映射物理地址到用户空间
* alt_read_word: 从指定寄存器读取一个值
* alt_write_word: 写入一个值到指定寄存器
* munmap:清除内存映射
* close:关闭设备驱动
通过一些宏访问寄存器
* alt_setbits_word:设定制定寄存器的指定位为1
* alt_clrbits_word:设定制定寄存器的指定位为0
配置LED引脚为输出引脚
alt_setbits_word( (virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DDR_ADDR ) & ( uint32_t)( HW_REGS_MASK ) ) ), USER_IO_DIR );
点亮LED
alt_setbits_word( (virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t)( HW_REGS_MASK ) ) ), BIT_LED );
读取KEY值
alt_read_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_EXT_PORTA_ADDR ) & ( uint_t )( HW_REGS_MASK ) ) ) );
main.c
#include
#include
#include
#include
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
#include "socal/alt_gpio.h"
#define HW_REGS_BASE ( ALT_STM_OFST )
#define HW_REGS_SPAN ( 0x04000000 )
#define HW_REGS_MASK ( HW_REGS_SPAN - 1 )
#define USER_IO_DIR (0x01000000)
#define BIT_LED (0x01000000)
#define BUTTON_MASK (0x02000000)
int main(int argc, char **argv) {
void *virtual_base;
int fd;
uint32_t scan_input;
int i;
// 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 );
}
// initialize the pio controller
// led: set the direction of the HPS GPIO1 bits attached to LEDs to output
alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DDR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), USER_IO_DIR );
printf("led test\r\n");
printf("the led flash 2 times\r\n");
for(i=0;i<2;i++)
{
alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
usleep(500*1000);
alt_clrbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
usleep(500*1000);
}
printf("user key test \r\n");
printf("press key to control led\r\n");
while(1){
scan_input = alt_read_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_EXT_PORTA_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ) );
//usleep(1000*1000);
if(~scan_input&BUTTON_MASK)
alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
else alt_clrbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
}
// 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 );
}
Makefile
#
TARGET = hps_gpio
#
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -g -Wall -I ${SOCEDS_DEST_ROOT}/ip/altera/hps/altera_hps/hwlib/include
LDFLAGS = -g -Wall
CC = $(CROSS_COMPILE)gcc
ARCH= arm
build: $(TARGET)
$(TARGET): main.o
$(CC) $(LDFLAGS) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -f $(TARGET) *.a *.o *~
本章实现HPS与FPGA交互。
使用HPS控制FPGA的10颗LED灯闪烁60次
FPGA端的PIO控制器pio_led连接到HPS/ARM lightweight axi bridge,获得在HPS/ARM总线上的物理地址空间。linux通过内核memory-mapped device驱动访问PIO控制器pio_led的寄存器物理地址,从而控制pio_led【同软件实验二】
generate_hps_qsys_header.sh
#!/bin/sh
export PATH=$PATH:/cygdrive/d/altera/quartus13.1/quartus/sopc_builder/bin
sopc-create-header-files "./soc_system.sopcinfo" --single hps_0.h --module hps_0
注意hps0.h和main.c及Makefile在一个文件夹中
main.c
#include
#include
#include
#include
#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 );
}
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;
led_mask = 0x01;
led_direction = 0; // 0: left to right direction
while( loop_count < 60 ) {
// control led, add ~ because the led is low-active
*(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 );
}
Makefile
#
TARGET = my_first_hps-fpga
#
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -static -g -Wall -I${SOCEDS_DEST_ROOT}/ip/altera/hps/altera_hps/hwlib/include
LDFLAGS = -g -Wall
CC = $(CROSS_COMPILE)gcc
ARCH= arm
build: $(TARGET)
$(TARGET): main.o
$(CC) $(LDFLAGS) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -f $(TARGET) *.a *.o *~