Xilinux PS与PL交互::Linux-App读写REG

背景

PL配置好有关的硬件,PS端做验证。

设计方案:针对REG地址,不使用设备树配置。

遇到的问题:暂无。

验证目的

验证PL-PS的各种交互方式。

这一块的验证是高级的,因为需要用到Linux驱动的有关框架,规范一点还需要配合设备树工作

验证思路

1、验证地址的读写是否有问题,之前用过Memory Access工具,可以直接对物理地址进行读写。

2、编写Linux驱动,达到一样的效果。

操作记录

Vivado、SDK、PetaLinux

无。

实际上,我在SDK中:

  • 1、 在helloWorld中验证了读写PL给出的内容
  • 2、使用中断例程,验证了来自PL端的按键中断工作正常。

Linux

MA小工具

本来是想自己写的,写到一半的时候不想处理文本转整数,因此在github上找到了一个MA工具:

实际上,Busybox中有一个devmem的程序同样可以达到这个目的。

/*
# Copyright By S.Ishihara, All Rights Reserved
# https://github.com/sig-ishihara/linux_pysical_address_rw_cmd.git
#
# File Name: ma.c
# Created : Dec 26, 2011
*/ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #define DEV_PATH "/dev/mem" int main(int argc, char *argv[])
{
int opt;
extern char *optarg;
extern int optind, opterr;
int width = 4; /* default byte access */
unsigned int memaddr, wdata;
unsigned int pgoffset, pgaddr;
unsigned int pagesize = sysconf(_SC_PAGESIZE);
unsigned char *p;
int fd; while ((opt = getopt(argc, argv, "w:")) != -1) {
if (opt == 'w') {
width = atoi(optarg);
} else {
goto error;
}
} argc -= optind;
argv += optind; fd = open(DEV_PATH, O_RDWR);
if (fd <= 0) {
fprintf(stderr, "open error: %s\n", DEV_PATH);
return 1;
} if (argc == 1) {
/* Read Mem */
memaddr = strtoul(argv[0], NULL, 16);
pgoffset = memaddr & (pagesize -1);
pgaddr = memaddr & ~(pagesize -1);
p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, pgaddr);
if (p < 0) {
fprintf(stderr, "mmap error\n");
return 1;
}
if (width == 1) {
printf("0x%08x: 0x%02x\n", memaddr, *(p + pgoffset));
} else if (width == 2) {
printf("0x%08x: 0x%04x\n", memaddr, *((unsigned short *)(p + pgoffset)));
} else if (width == 4) {
printf("0x%08x: 0x%08x\n", memaddr, *((unsigned int *)(p + pgoffset)));
} else {
goto error;
}
} else if (argc == 2) {
/* Write Mem */
memaddr = strtoul(argv[0], NULL, 16);
pgoffset = memaddr & (pagesize -1);
pgaddr = memaddr & ~(pagesize -1);
p = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, fd, pgaddr);
if (p < 0) {
fprintf(stderr, "mmap error\n");
return 1;
}
wdata = strtoul(argv[1], NULL, 16);
if (width == 1) {
*(p + pgoffset) = (unsigned char)wdata;
} else if(width == 2) {
*((unsigned short *)(p + pgoffset)) = (unsigned short)wdata;
} else if(width == 4) {
*((unsigned int *)(p + pgoffset)) = (unsigned int)wdata;
} else {
goto error;
}
} else {
goto error;
} munmap(p, pagesize);
close(fd);
return 0; error:
printf("Usage: Mem [-w WIDTH] ADDRESS [DATA]\n"
"Mem read or write.\n"
" -w number of byte width. permit 1, 2, 4(default)\n"
"\n"
"This command executable only root user.\n"
"Mem address possible range 32bit.\n"
"\n"
"Examples:\n"
" Mem a0000 Read memory from address 0xa0000.\n"
" Mem -w1 a0000 31 Write memory address 0xa0000 to 0x31.\n"
" Mem 20000 5a5a5a5a Write memory address 0x20000 to 0x5a5a5a5a.\n"
"\n");
return 1;
}

编译通过以后,对AXI地址进行验证:

1、写入再读出AXI-REG,正常:

#define XPAR_M_AVALON_0_BASEADDR 0x43C00000

# 读取
./md 0x43C00000
0x43c00000: 0x00 # 写入
./md 0x43C00000 1 # 再读取
./md 0x43C00000
0x43c00000: 0x01

2、读取PL按键正常:

#define XPAR_AXI_GPIO_1_BASEADDR 0x41210000

# 读取(未按下)
./md 0x41210000
0x41210000: 0x01
# 读取(未按下)
./md 0x41210000
0x41210000: 0x00

3、控制LED灯,正常:

#define XPAR_AXI_GPIO_0_BASEADDR 0x41200000

# 开启
./md 0x41200000 1 # 关闭
./md 0x41200000 0

地址读写驱动

在MA控制正常以后,转而使用驱动来处理。

以下的驱动仅实现了 AXI-LED 灯的控制,但是已经能够作为一个简单的地址读写

待完善:一片内存的读写,read、write方法

模块
#
# File Name: mymodule.c
# Created : 2020-07-27 09:19:51
# Usage :
# insmod modulexx.ko
# then
# cat /proc/devices
*/ #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h> #include <linux/printk.h> #include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h> #include <linux/io.h>
#include <linux/uaccess.h> //#include <linux/slab.h>
#include <asm/io.h> #define ZYNQ_AXI_ON _IOW('L', 1, unsigned long)
#define ZYNQ_AXI_OFF _IOW('L', 2, unsigned long) #define XPAR_AXI_GPIO_0_BASEADDR 0x41200000 // LED _out
// todo
#define XPAR_AXI_GPIO_1_BASEADDR 0x41210000 // Btn _in
#define XPAR_M_AVALON_0_BASEADDR 0x43C00000 // REG_I/O /*
# 开启
./md 0x41200000 1 # 关闭
./md 0x41200000 0
*/ static struct cdev zynq_axi_cdev;
static unsigned int axi_major = 0;
static unsigned int axi_minor = 0;
static dev_t axi_num;
static struct class* axi_class;
static struct device* axi_device;
static struct resource* axi_res; static void __iomem * axi_led_base_va;
#if 0
static void __iomem * axi_reg_base_va;
static void __iomem * axi_btn_base_va;
#endif
static char *temp = NULL; #define XPAR_M_AVALON_0_BASEADDR 0x43C00000
#define XPAR_M_AVALON_0_HIGHADDR 0x43C0FFFF #define AXI_REG (XPAR_AXI_GPIO_0_BASEADDR)
#define AXI_REG_SIZE 1 //(XPAR_M_AVALON_0_HIGHADDR - XPAR_M_AVALON_0_BASEADDR) int zynq_axi_open(struct inode *inode, struct file *file) {
return 0;
} #if 0
switch(args){
case 8:
writel(readl(axi_led_out_va) | (1<<17), axi_led_out_va);
break;
case 9:
writel(readl(axi_led_out_va) | (1<<8), axi_led_out_va);
break;
case 10:
writel(readl(axi_led_out_va) | (1<<7), axi_led_out_va);
break;
case 11:
writel(readl(axi_led_out_va) | (1<<12), axi_led_out_va);
break;
default:
return -EINVAL;
}
#endif long zynq_axi_ioctl(struct file *file, unsigned int cmd, unsigned long args) { switch(cmd) {
case ZYNQ_AXI_ON:
writel(1, axi_led_base_va);
break;
case ZYNQ_AXI_OFF:
writel(0, axi_led_base_va);
break;
default:
return -ENOIOCTLCMD;
} return 0;
} static ssize_t zynq_axi_read(struct file *filep, char __user *buf, size_t len, loff_t *pos) { if( len > 64)
{
len = 64;
} #if 0
if(copy_to_user(buf, temp, len))
{
return -EFAULT;
}
#endif return len;
} static ssize_t zynq_axi_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos) { if( len > 64) {
len = 64;
} if(copy_from_user(buf, temp, len)) {
return -EFAULT;
} printk("<4>" "write %s\n",temp);
return len;
} static const struct file_operations zynq_axi_ops = {
.owner = THIS_MODULE,
.open = zynq_axi_open,
.read = zynq_axi_read,
.write = zynq_axi_write,
.unlocked_ioctl = zynq_axi_ioctl,
}; static int __init zynq_axi_init(void) {
int retval;
if(axi_major == 0)
retval = alloc_chrdev_region(&axi_num, axi_minor, 1, "axi_device");
else {
axi_num = MKDEV(axi_major, axi_minor);
retval = register_chrdev_region(axi_num, 1, "axi_device");
} if(retval < 0) {
printk("can not get device number\n");
goto chrdev_region_error;
} cdev_init(&zynq_axi_cdev, &zynq_axi_ops); retval = cdev_add(&zynq_axi_cdev, axi_num, 1);
if(retval < 0) {
printk(KERN_WARNING "cdev_add error\n");
goto cdev_add_error;
} axi_class = class_create(THIS_MODULE, "zynq_axi_class");
if(axi_class == NULL) {
printk(KERN_WARNING "class_create error\n");
retval = -EBUSY;
goto class_create_error;
}
/*
cd / && find . -name "axi_drv"
./sys/devices/virtual/zynq_axi_class/axi_drv
./sys/class/zynq_axi_class/axi_drv
./dev/axi_drv
*/
axi_device = device_create(axi_class, NULL, axi_num, NULL, "axi_drv");
if(axi_device == NULL) {
retval = -EBUSY;
printk(KERN_WARNING "device_create error\n");
goto device_create_error;
} // 用于操作物理地址
axi_res = request_mem_region(AXI_REG, AXI_REG_SIZE, "axi_led_MEM"); // cat /proc/iomem
if(axi_res == NULL) {
retval = -EBUSY;
printk(KERN_WARNING "request_mem_region error\n");
goto request_mem_region_error;
} axi_led_base_va = ioremap(AXI_REG, AXI_REG_SIZE);
if(axi_led_base_va == NULL){
retval = -EBUSY;
printk(KERN_WARNING "ioremap error\n");
goto ioremap_error;
} //temp = kmalloc(sizeof(char) * 64, GFP_KERNEL); #if 0
// 可供参考
axi_led_out_va = axi_led_base_va + 0x00;
axi_led_outenb_va = axi_led_base_va + 0x04;
axi_led_altfn0_va = axi_led_base_va + 0x20;
axi_led_altfn1_va = axi_led_base_va + 0x24; temp = readl(axi_led_altfn0_va);
temp &= ~((3<<14) | (3<<16) | (3<<24));
temp |= ((1<<14) | (1<<16) | (1<<24));
writel(temp, axi_led_altfn0_va); temp = readl(axi_led_altfn1_va);
temp &= ~(3<<2);
temp |= (1<<2);
writel(temp, axi_led_altfn1_va); //将GPIOC17 GPIOC8 GPIOC7 GPIOC12设置为输出
temp = readl(axi_led_outenb_va);
temp |= ((1<<17) | (1<<8) | (1<<7) | (1<<12));
writel(temp, axi_led_outenb_va); //将GPIOC17 GPIOC8 GPIOC7 GPIOC12输出高电平
temp = readl(axi_led_out_va);
temp |= ((1<<17) | (1<<8) | (1<<7) | (1<<12));
writel(temp, axi_led_out_va);
#endif printk(KERN_WARNING "zynq_axi_init\n"); return 0; ioremap_error:
release_mem_region(AXI_REG, AXI_REG_SIZE);
axi_res = NULL;
request_mem_region_error:
device_destroy(axi_class, axi_num);
axi_device = NULL;
device_create_error:
class_destroy(axi_class);
axi_class = NULL;
class_create_error:
cdev_del(&zynq_axi_cdev);
cdev_add_error:
unregister_chrdev_region(axi_num, 1);
chrdev_region_error:
return retval;
} static void __exit zynq_axi_exit(void) {
iounmap(axi_led_base_va);
release_mem_region(AXI_REG, AXI_REG_SIZE);
axi_res = NULL;
device_destroy(axi_class, axi_num);
axi_device = NULL;
class_destroy(axi_class);
axi_class = NULL;
cdev_del(&zynq_axi_cdev);
unregister_chrdev_region(axi_num, 1);
//kfree(temp);
printk(KERN_WARNING "zynq_axi_exit\n");
} module_init(zynq_axi_init);
module_exit(zynq_axi_exit); MODULE_AUTHOR("Schips for ITC");
MODULE_DESCRIPTION("Zynq axi Device Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");
应用程序
#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h> #define ZYNQ_AXI_ON _IOW('L', 1, unsigned long)
#define ZYNQ_AXI_OFF _IOW('L', 2, unsigned long) int main(int argc, char * argv[])
{
int fd;
int i; fd = open("/dev/axi_drv", O_RDWR);
if(fd < 0)
{
perror("open fail \n");
return -1;
} for (i = 0; i < 5; ++i)
{
ioctl(fd, ZYNQ_AXI_ON);
printf("On\n");
sleep(1);
} close(fd);
return 0;
}

情况正常。

Xilinux PS与PL交互::Linux-App读写REG的更多相关文章

  1. 78.PL和PS通过BRAM交互共享数据

    本篇文章目的是使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果 ...

  2. [原创]基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程

    基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程 待添加完善中

  3. MiZ702学习笔记13——ZYNQ通过AXI-Lite与PL交互

    在<MiZ702学习笔记7——尝试自制带总线IP>,我曾提到了AXI4-Lite的简单用法,驱动了下流水灯,只涉及到了写总线.今天,我想利用之前的VGA模块,将AXI4-Lite的读写都应 ...

  4. zedboard通过BRAM实现PS和PL的简单通信

    使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果打印输出到串口 ...

  5. [mysql]linux mysql 读写分离

    [mysql]linux mysql 读写分离 作者:flymaster qq:908601287 blog:http://www.cnblogs.com/flymaster500/ 1.简介 当今M ...

  6. Linux下ps命令详解 Linux下ps命令的详细使用方法

    http://www.jb51.net/LINUXjishu/56578.html Linux下的ps命令比较常用 Linux下ps命令详解Linux上进程有5种状态:1. 运行(正在运行或在运行队列 ...

  7. 使用axi_datamover完成ZYNQ片内PS与PL间的数据传输

    分享下PS与PL之间数据传输比较另类的实现方式,实现目标是: 1.传输时数据不能滞留在一端,无论是1个字节还是1K字节都能立即发送: 2.PL端接口为FIFO接口: PS到PL的数据传输流程: PS到 ...

  8. zedboard如何从PL端控制DDR读写(六)

    上一节说到了DDR寻址的问题,如下图: 从官方文档上我们看到了DDR的地址是从0008_0000开始的,那么我们开始修改Xilinx给我们提供的IP核代码.其实很简单,上一节已经分析了地址停留在000 ...

  9. 从零开始学ios开发(三):第一个有交互的app

    感谢大家的关注,也给我一份动力,让我继续前进.有了自己的家庭有了孩子,过着上有老下有小的生活,能够挤出点时间学习真的很难,每天弄好孩子睡觉已经是晚上10点左右了,然后再弄自己的事情,一转眼很快就到12 ...

  10. Zynq PS和PL间的连接

    跨越PS和PL的信号 AXI总线.EMIO.其他(看门狗.重启信号.中断信号.DMA接口信号) AXI标准 AXI(高级可扩展接口)是ARM AMBA的一部分.AMBA总线主要用于片上系统.AXI总线 ...

随机推荐

  1. SAP集成技术(十二)SAP PO

    集成工作的一个重要部分是基于流程的集成,而在SAP环境中实现接口需求的众所周知的产品是SAP Process Orchestration(以下简称SAP PO). 现代集成架构通常使用中央系统来控制和 ...

  2. JUC并发编程学习笔记(二)Lock锁(重点)

    Lock锁(重点) 传统的synchronized 传统的解决多线程并发导致的一些问题我们会使用synchronized关键字来解决,synchronized的本质就是队列.锁. Lock的实现类有: ...

  3. go1.18泛型全部教程

    目录 go1.18泛型全部教程 一 什么是泛型 二 Golang中的泛型 三 泛型语法详解 3.1 泛型的语法 3.2 Constraint(约束)是什么 3.3 自定义constraint(约束) ...

  4. gRPC入门学习之旅(八)

    gRPC入门学习之旅(一) gRPC入门学习之旅(二) gRPC入门学习之旅(三) gRPC入门学习之旅(四) gRPC入门学习之旅(五) gRPC入门学习之旅(六) gRPC入门学习之旅(七) 3. ...

  5. ES 2024 新特性

    ECMAScript 2024 新特性 ECMAScript 2024, the 15th edition, added facilities for resizing and transferrin ...

  6. Cookie的过期时间为Session在微信浏览器失效

    前言 最近一次迭代上线,结果临了上线当晚,被我无疑间发现一个bug,之前测试小伙伴没测出来.Cookie的过期时间为Session在微信浏览器失效 ..net framework webform 项目 ...

  7. Python基础篇(数据类型)

    str(字符串) Python中最常用的数据类型就是字符串,其用途也很多,我们可以使用单引号 ''或者双引号""来创建字符串.字符串是不可修改的.关于字符我们从 创建.索引.切片. ...

  8. 高效运维_AIRIOT智慧电力运维解决方案

    可再生能源的引入带来了能源生产的去中心化和分散化趋势,同时也带来了能源输出的波动性和不确定性.电力运维因此需要更加灵活.智能的解决方案,以适应可再生能源的集成,确保电力系统的稳定运行,传统的电力运维管 ...

  9. jenkens

    [root@mcw01 ~]$ ls .jenkins/ config.xml jenkins.install.UpgradeWizard.state nodeMonitors.xml secret. ...

  10. JS / jQuery 刷新页面的方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...