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. JUC并发编程学习笔记(十八)深入理解CAS

    深入理解CAS 什么是CAS 为什么要学CAS:大厂你必须深入研究底层!有所突破! java层面的cas------->compareAndSet compareAndSet(int expec ...

  2. 五:瑞芯微RV1109

    瑞芯微RV1109是一款用于工控机或人工智能视觉应用的高性能机器视觉处理器SoC. 参考资料 http://www.neardi.com/news_22/434.html https://www.ro ...

  3. 【GUI软件】小红书按关键词采集笔记详情,支持多个关键词,含笔记正文、转评赞藏等

    目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集-搜索接口 2.2 爬虫采集-详情接口 2.3 cookie说明 2.4 软件界面模块 2.5 ...

  4. CompletableFuture学习总结

    CompletableFuture 简介 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通 ...

  5. SpringBoot-EasyExcel导出数据(带图片)

    前言 EasyExcel 是阿里巴巴开源的一个Java操作Excel的技术,和EasyPoi一样是封装Poi的工具类. 但是不同的地方在于,在EasyExcel中解决了Poi技术读取大批量数据耗费内存 ...

  6. nim 5. 读写文件

    读文件 假设nim程序相同的文件夹下,有个people.txt文件,内容如下: Alice A. Bob B. Carol C. 读取这个文件的代码 import strutils let conte ...

  7. LLM生态下爬虫程序的现状与未来

    最近出现一批与LLM有关的新的爬虫框架,一类是为LLM提供内容抓取解析的,比如 Jina Reader 和 FireCrawl ,可以将抓取的网页解析为markdown这样的对LLM友好的内容,例如m ...

  8. java学习之旅(day.20)

    注解和反射 注释comment:给人看 注解annotation:不仅可以给人看,还能给程序看,甚至能被其他程序读取 注解入门 什么是注解 注解的作用: 不是程序本身,可以对程序作出解释(这一点和注释 ...

  9. 精准管控|AIRIOT数字油库智能化解决方案

      在油库管理的过程中,储油罐区普遍存在分布空间范围广.安全防爆要求高.监控点多.布线复杂.自动化系统集成难度大等问题,传统的油库管理手段相对落后.管理环境复杂,企业在监测监控.设备设施管理.日常运行 ...

  10. 查看浏览器对html5的支持情况

    http://html5test.com/   视频和音频代码检测 function CheckAudio(){ var myAudio=document.createElement("au ...