您的位置:首页 > 其它

ZYNQ Z-TURN BOARD 学习笔记1-Ubuntu上的流水灯实验

2016-07-24 11:20 411 查看
前言

之前一直都在学习传统的FPGA,学习和使用过Altera的Cyclone系列以及Xilinx的Spartan系列芯片。对于赛灵思的软硬件全面可编程器件ZYNQ很有兴趣,但苦于手头没有zynq的板子,一直没能体验。前不久在某群里发现有人转手米尔科技的z-turn开发板,于是走闲鱼渠道,入手了这块开发板。博主对于ARM嵌入式技术是个新手,因此在学习zynq 的同时,也同时在学习基础的嵌入式Linux技术。这篇博客里会详细地记录本人学习中遇到的许多前辈看起来很低级的问题,还请大家多多指教。

Z-TURN开发板简介

z-turn是深圳米尔科技设计的一款开发板。开发板的硬件布局如下图所示:



对这块板子摸索了几天,感觉这块板子外设接口不够丰富,没有电源开关,HDMI接口只能外接HDMI显示器,对HDMI转DVI不兼容,因为它的显示驱动是挂载在zynq 的可编程逻辑(PL)上的,使用了xylon的评估版IP核,并不是由ARM A9核心驱动的。

流水灯实验

硬件设备:PC机,开发板,mini USB连接线,miniUSB接口的OTG线,一块U盘(或者读卡器加TF卡)

主要软件:vmware虚拟机,Ubuntu系统,hyper terminal串口终端,SSH Secure File Transfer Client,用于Windows和虚拟机上Ubuntu系统之间的文件互传。

实验步骤:

之前学习另外的ARM A9开发板的时候,PC端 的虚拟机上已经加载了一个Ubuntu系统的镜像,这次做zynq的实验,需要在虚拟机Ubuntu上安装Xilinx的arm-linux交叉编译器。另外,开发板的TF卡上出厂的时候已经烧录了一个Ubuntu系统,实验中,开发板就是直接从TF卡中启动Ubuntu系统的。

1.PC端Ubuntu安装Xilinx交叉编译器

先将Xilinx提供的编译器压缩包通过ssh拷到PC端Ubuntu内

$tar -xvjf Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux.tar.bz2解压压缩包,

$export PATH=$PATH:<WORKDIR>/Toolchain/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin

$export CROSS_COMPILE=arm-xilinx-linux-gnueabi-添加编译器的环境变量。设置完以后输入arm-x再按tab键,自动出现rm-xilinx-linux-gnueabi-则说明安装编译器成功了。这次安装只是暂时安装了,如果关闭虚拟机,下次再开启虚拟机和Ubuntu时,还要重新安装编译器。永久性地安装编译器可以在bashrc文件添加编译器的环境变量:

$ cd 回到用户主目录,$ vim .bashrc 打开bashrc文件,按insert进入输入模式,添加export PATH=$PATH:<WORKDIR>/Toolchain/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin 按esc退出输入模式,:wq保存并退出,这样就永久性地安装好了Xilinx的交叉编译器。

2.在PC端Ubuntu上编译led-test.c文件,得到可执行文件。

先在Windows上编辑好led-test.c文件
/*****************************************************************************
* Copyright (c) 2014-2017 MYIR Tech Ltd.
*        File: led-test.c
*        Date: 2014/11/3
*      Author: Kevin Su
* Description: A demo program to show how to control leds from user-space.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <linux/input.h>

#define DEBUG	1

#define ERR_MSG(fmt, args...)	fprintf(stderr, fmt, ##args)
#ifdef DEBUG
#define DBG_MSG(fmt, args...)	fprintf(stdout, fmt, ##args)
#else
#define DBG_MSG(fmt, args...)
#endif

#define LED1_DIR	"/sys/class/leds/usr_led1/"
#define LED2_DIR	"/sys/class/leds/usr_led2/"
#define LEDR_DIR	"/sys/class/leds/led_r/"
#define LEDG_DIR	"/sys/class/leds/led_g/"
#define LEDB_DIR	"/sys/class/leds/led_b/"
#define NAME_MAX_LENGTH		64
#define LED_DELAY_US	(100*1000)

#define ARRAY_SIZE(x)	(sizeof(x)/sizeof(x[0]))

#define BITS_MASK(num)	((1<<num) - 1)

typedef struct led_ctrl_s {
char name[NAME_MAX_LENGTH];
char brightness[NAME_MAX_LENGTH];
char trigger[NAME_MAX_LENGTH];
char trigger_backup[NAME_MAX_LENGTH];
int state;
int initialized;
} led_ctrl_t;

static led_ctrl_t leds[] = {
/* name, brightness, trigger, trigger_str,  state, initialized */
{"usr_led1", LED1_DIR "brightness", LED1_DIR "trigger", "", 0, 0},
{"usr_led2", LED2_DIR "brightness", LED2_DIR "trigger", "", 0, 0},
{"led_r", LEDR_DIR "brightness", LEDR_DIR "trigger", "", 0, 0},
{"led_g", LEDG_DIR "brightness", LEDG_DIR "trigger", "", 0, 0},
{"led_b", LEDB_DIR "brightness", LEDB_DIR "trigger", "", 0, 0}
};

static int led_set_trigger(led_ctrl_t *led, const char *trigger)
{
int ret;
int fd = open(led->trigger, O_WRONLY);

if (fd < 0) {
ERR_MSG("Open %s failed!\n", led->trigger);
return -1;
}

ret = write(fd, trigger, strlen(trigger));
if (ret != strlen(trigger)) {
ERR_MSG("Write %s failed!\n", led->trigger);
close(fd);
return -1;
}
close(fd);
DBG_MSG("[%8s] Set trigger to '%s'\n",
led->name,
trigger);

return 0;
}

static int led_get_trigger(led_ctrl_t *led, char *trigger)
{
int ret;
char tmp[128] = {0};
char *ptr[2] = {NULL};
int fd = open(led->trigger, O_RDONLY);

if (fd < 0) {
ERR_MSG("Open %s failed!\n", led->trigger);
return -1;
}

/* read back string with format like: "none cpu1 cpu2 [heartbeat] nand" */
ret = read(fd, tmp, sizeof(tmp));
if (ret <= 0) {
ERR_MSG("Read %s failed!\n", led->trigger);
close(fd);
return -1;
}
close(fd);

/* find trigger from read back string, which is inside "[]" */
ptr[0] = strchr(tmp, '[');
if (ptr[0]) {
ptr[0] += 1;
ptr[1] = strchr(ptr[0], ']');
if (ptr[1]) {
*ptr[1] = '\0';
} else {
ERR_MSG("[%s] Can not find trigger in %s!\n", led->name, tmp);
return -1;
}
strcpy(trigger, ptr[0]);
} else {
ERR_MSG("[%s] Can not find trigger in %s!\n", led->name, tmp);
return -1;
}

DBG_MSG("[%8s] Get trigger: '%s'\n",
led->name,
trigger);

return 0;
}

static int led_set_brightness(led_ctrl_t * led, int brightness)
{
int ret;
int fd = open(led->brightness, O_WRONLY);
char br_str[2] = {0};

br_str[0] = '0' + brightness;

if (fd < 0) {
ERR_MSG("Open %s failed!\n", led->brightness);
return -1;
}

ret = write(fd, br_str, sizeof(br_str));
if (ret != sizeof(br_str)) {
ERR_MSG("Write %s failed!\n", led->brightness);
close(fd);
return -1;
}
close(fd);
// DBG_MSG("[%s] Set brightness to %s successfully!\n",
// led->name,
// br_str);

return 0;
}

static int led_init(void)
{
int i;
char tmp[NAME_MAX_LENGTH];

for (i=0; i<ARRAY_SIZE(leds); i++) {
memset(tmp, 0, sizeof(tmp));

/* Backup all led triggers */
if (led_get_trigger(&leds[i], tmp)) {
return -1;
}
strcpy(leds[i].trigger_backup, tmp);

/* Set all led triggers to 'none' */
if (led_set_trigger(&leds[i], "none")) {
return -1;
}

/* Set all brightness to 0 */
if (led_set_brightness(&leds[i], 0)) {
return -1;
}
leds[i].state = 0;
leds[i].initialized = 1;
}
return 0;
}

static void led_restore(void)
{
int i;

/* set all brightness to '0', and restore triggers */
for (i=0; i<ARRAY_SIZE(leds); i++) {
if (leds[i].initialized) {
led_set_brightness(&leds[i], 0);
led_set_trigger(&leds[i], leds[i].trigger_backup);
}
}
}

/* Will be called if SIGINT(Ctrl+C) and SIGTERM(simple kill) signal is received */
static void signal_callback(int num)
{
led_restore();
exit(num);
}

int main(int argc, const char *argv[])
{
unsigned int led_bits = 0x1;
const int led_num = ARRAY_SIZE(leds);
int i;

/* Open button device */
if(led_init()) {
led_restore();
return -1;
}

/* Register SIGINT(Ctrl+C) and SIGTERM(simple kill) signal and signal handler */
signal(SIGINT, signal_callback);
signal(SIGTERM, signal_callback);

for (;;) {
for (i=0; i<led_num; i++) {
if (led_bits&(1<<i)) { /* this led should be turn ON */
if (leds[i].state == 0) { /* if already ON, do nothing */
leds[i].state = 1;
led_set_brightness(&leds[i], leds[i].state);
}
} else { /* this led should be turn OFF */
if (leds[i].state == 1) { /* if already OFF, do nothing */
leds[i].state = 0;
led_set_brightness(&leds[i], leds[i].state);
}
}
}
usleep(LED_DELAY_US);
/* do the rotate left */
led_bits = ((led_bits << 1) & BITS_MASK(led_num))
| ((led_bits>>(led_num-1)) & 0x1);
}

led_restore();

return 0;
}
然后通过ssh将源文件拷进虚拟机Ubuntu,

$arm-xilinx-linux-gnueabi- gcc -o led led-test.c编译生成了一个可在开发板上运行的名为led的可执行文件。将这个文件拷贝的Windows,再拷贝到U盘里面。这个U盘事先最好用HP USB Disk Storage Format Tool 软件格式化一下。

3.开发板Ubuntu上挂载U盘并运行可执行文件

挂载U盘这一步折腾博主蛮久时间。

启动开发板后,将U盘通过OTG线插入开发板,$fdisk -l查看所有的存储设备,发现了U盘在/dev路径下面,名为sda(这里不同的情况下可能名称不同,可以通过容量来确定哪一个设备是自己插入的)

$ mount /dev/sda /mnt/udisk udisk是博主在mnt路径下新建的文件夹,用来挂载U盘。执行这个指令后各种报错,折腾了蛮久,后来进入dev文件夹下看到sda后面还有一个sda1,于是就尝试mount了一下sda1,结果挂载成功了,用df指令可以看到sda1这个设备。不知道是为什么。最后进入udisk,找到led可执行文件, ./led执行文件。顺利运行,led开始流水闪烁。串口终端打印出相应的信息:

[usr_led1] Get trigger: 'none'

[usr_led1] Set trigger to 'none'

[usr_led2] Get trigger: 'none'

[usr_led2] Set trigger to 'none'

[ led_r] Get trigger: 'heartbeat'

[ led_r] Set trigger to 'none'

[ led_g] Get trigger: 'heartbeat'

[ led_g] Set trigger to 'none'

[ led_b] Get trigger: 'heartbeat'

[ led_b] Set trigger to 'none'

开发板现象如下图:



上图中,红色miniUSB线接电脑USB接口,起串口调试和供电作用,事先需要在电脑端安装USB转串口驱动。蓝色OTG线用于连接U盘。

整个实验到此结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: