Xilinux PS与PL交互::Linux-App读写REG
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的更多相关文章
- 78.PL和PS通过BRAM交互共享数据
本篇文章目的是使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果 ...
- [原创]基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程
基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程 待添加完善中
- MiZ702学习笔记13——ZYNQ通过AXI-Lite与PL交互
在<MiZ702学习笔记7——尝试自制带总线IP>,我曾提到了AXI4-Lite的简单用法,驱动了下流水灯,只涉及到了写总线.今天,我想利用之前的VGA模块,将AXI4-Lite的读写都应 ...
- zedboard通过BRAM实现PS和PL的简单通信
使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果打印输出到串口 ...
- [mysql]linux mysql 读写分离
[mysql]linux mysql 读写分离 作者:flymaster qq:908601287 blog:http://www.cnblogs.com/flymaster500/ 1.简介 当今M ...
- Linux下ps命令详解 Linux下ps命令的详细使用方法
http://www.jb51.net/LINUXjishu/56578.html Linux下的ps命令比较常用 Linux下ps命令详解Linux上进程有5种状态:1. 运行(正在运行或在运行队列 ...
- 使用axi_datamover完成ZYNQ片内PS与PL间的数据传输
分享下PS与PL之间数据传输比较另类的实现方式,实现目标是: 1.传输时数据不能滞留在一端,无论是1个字节还是1K字节都能立即发送: 2.PL端接口为FIFO接口: PS到PL的数据传输流程: PS到 ...
- zedboard如何从PL端控制DDR读写(六)
上一节说到了DDR寻址的问题,如下图: 从官方文档上我们看到了DDR的地址是从0008_0000开始的,那么我们开始修改Xilinx给我们提供的IP核代码.其实很简单,上一节已经分析了地址停留在000 ...
- 从零开始学ios开发(三):第一个有交互的app
感谢大家的关注,也给我一份动力,让我继续前进.有了自己的家庭有了孩子,过着上有老下有小的生活,能够挤出点时间学习真的很难,每天弄好孩子睡觉已经是晚上10点左右了,然后再弄自己的事情,一转眼很快就到12 ...
- Zynq PS和PL间的连接
跨越PS和PL的信号 AXI总线.EMIO.其他(看门狗.重启信号.中断信号.DMA接口信号) AXI标准 AXI(高级可扩展接口)是ARM AMBA的一部分.AMBA总线主要用于片上系统.AXI总线 ...
随机推荐
- JUC并发编程学习笔记(十八)深入理解CAS
深入理解CAS 什么是CAS 为什么要学CAS:大厂你必须深入研究底层!有所突破! java层面的cas------->compareAndSet compareAndSet(int expec ...
- 五:瑞芯微RV1109
瑞芯微RV1109是一款用于工控机或人工智能视觉应用的高性能机器视觉处理器SoC. 参考资料 http://www.neardi.com/news_22/434.html https://www.ro ...
- 【GUI软件】小红书按关键词采集笔记详情,支持多个关键词,含笔记正文、转评赞藏等
目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集-搜索接口 2.2 爬虫采集-详情接口 2.3 cookie说明 2.4 软件界面模块 2.5 ...
- CompletableFuture学习总结
CompletableFuture 简介 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通 ...
- SpringBoot-EasyExcel导出数据(带图片)
前言 EasyExcel 是阿里巴巴开源的一个Java操作Excel的技术,和EasyPoi一样是封装Poi的工具类. 但是不同的地方在于,在EasyExcel中解决了Poi技术读取大批量数据耗费内存 ...
- nim 5. 读写文件
读文件 假设nim程序相同的文件夹下,有个people.txt文件,内容如下: Alice A. Bob B. Carol C. 读取这个文件的代码 import strutils let conte ...
- LLM生态下爬虫程序的现状与未来
最近出现一批与LLM有关的新的爬虫框架,一类是为LLM提供内容抓取解析的,比如 Jina Reader 和 FireCrawl ,可以将抓取的网页解析为markdown这样的对LLM友好的内容,例如m ...
- java学习之旅(day.20)
注解和反射 注释comment:给人看 注解annotation:不仅可以给人看,还能给程序看,甚至能被其他程序读取 注解入门 什么是注解 注解的作用: 不是程序本身,可以对程序作出解释(这一点和注释 ...
- 精准管控|AIRIOT数字油库智能化解决方案
在油库管理的过程中,储油罐区普遍存在分布空间范围广.安全防爆要求高.监控点多.布线复杂.自动化系统集成难度大等问题,传统的油库管理手段相对落后.管理环境复杂,企业在监测监控.设备设施管理.日常运行 ...
- 查看浏览器对html5的支持情况
http://html5test.com/ 视频和音频代码检测 function CheckAudio(){ var myAudio=document.createElement("au ...