Linux下如何通过UIO监控PL给到PS的中断

嵌入式技术

1332人已加入

描述

1. 概述

xilinx mpsoc 平台中,PS 和 PL 进行交互时,PS 需要获取 PL 发出的中断信号。从 mpsoc 技术参考手册 ug1085 TRM 中可知,PL 给到 PS 的中断有两组——PL_PS_Group0 和 PL_PS_Group1,中断号范围分别为 121~128 和 136 ~143( 在 Linux 设备树中进行配置时,中断号要减去 32 )。

Linux

下面通过一个例程说明 如何通过 UIO 监控 PL 给到 PS 的中断

2. demo

Linux 环境下,获取 PL 中断信号最简单的方式是通过 UIO。这里,定义一个简单的测试 demo:

  1. Linux 下控制 AXI-GPIO 产生高低电平;
  2. PL 将 AXI-GPIO 的高低电平转变为中断信号给到 Linux。

2.1 vivado 配置

2.1.1 vivado

在 PL 端添加 AXI-GPIO IP 核,并使能两个通道,两个通道分别连接 PL_PS_Group0 和 PL_PS_Group1。

Linux

2.1.2 PL to PS Interrupts

使能 PL 给到 PS 的两组中断。

Linux

2.1.3 AXI GPIO 配置

使能 AXI GPIO 的两个通道,每个通道使用 1 位即可。

Linux

2.2 PS Linux

PS 端 Linux 系统下,通过 控制 AXI-GPIO 输出高低电平即可使 PL 生成中断信号到 PL_PS_Group0 和 PL_PS_Group1

2.2.1 AXI-GPIO 控制

Linux 下,AXI-GPIO 的控制方式和普通 GPIO 没有区别,最简单的方式是通过 /sys 文件系统。

cd /sys/class/gpio
#使能引脚号为506的引脚——将引脚导出到用户空间
echo 506 > export
#设置引脚为输出模式
echo out > gpio506/direction
#控制引脚输出高电平
echo 1 > gpio506/value
#控制引脚输出低电平
echo 0 > gpio506/value
#关闭引脚
echo 506 > unexport

Linux

2.2.2 设备树

在设备树中添加 UIO 中断节点,注意中断号的数值。

system-user.dtsi:

pl-ps-group0-1 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 89 1 >;
};
pl-ps-group0-2 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 90 1 >;
};

......

pl-ps-group0-8 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 96 1 >;
};

pl-ps-group1-1 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 104 1 >;
};
pl-ps-group1-2 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 105 1 >;
};

 ......

pl-ps-group1-8 {
    compatible = "generic-uio";
    interrupt-controller;
    interrupt-parent = < &gic >;
    interrupts = < 0 111 1 >;
};

Linux

2.2.3 中断监控程序

uio-int-monitor.c:

#include < stdio.h >
#include < stdlib.h >
#include < stdint.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#include < pthread.h >
#include < unistd.h >

#define PL_PS_GROUP0_0_UIO_NAME ("/dev/uio2")
#define PL_PS_GROUP1_0_UIO_NAME ("/dev/uio10")

struct uio_int_info {
    int8_t *uio_name;
    int32_t uio_fd;
};

static void *interrupt_uio_monitor(void *para)
{
    struct uio_int_info *uio_info = (struct uio_int_info *)para;
    const uint32_t uio_int_regen_flag = 1;
    uint32_t uio_int_happen_cnt = 0;

    write(uio_info- >uio_fd, &uio_int_regen_flag, sizeof(uio_int_regen_flag));

    while(1)
    {
        read(uio_info- >uio_fd, &uio_int_happen_cnt, sizeof(uio_int_happen_cnt));
        write(uio_info- >uio_fd, &uio_int_regen_flag, sizeof(uio_int_regen_flag));

        printf("%s interrupt happen, count:%un", uio_info- >uio_name, uio_int_happen_cnt);
    }
}

int main(int argc, char *argv[])
{
    pthread_t tid;
    struct uio_int_info g0_0 =
    {
        .uio_name = "gruop0-0",
    };

    struct uio_int_info g1_0 =
    {
        .uio_name = "gruop1-0",
    };

    g0_0.uio_fd = open(PL_PS_GROUP0_0_UIO_NAME, O_RDWR);
    g1_0.uio_fd = open(PL_PS_GROUP1_0_UIO_NAME, O_RDWR);

    if((-1 == g0_0.uio_fd) || (-1 == g1_0.uio_fd))
    {
        printf("open uio device failedn");
        return -1;
    }

    pthread_create(&tid, NULL, interrupt_uio_monitor, (void *)&g0_0);
    pthread_create(&tid, NULL, interrupt_uio_monitor, (void *)&g1_0);

    getchar();

    close(g0_0.uio_fd);
    close(g1_0.uio_fd);

    return 0;
}

重点说明:

  1. read(uio_fd) 用于监测中断信号;
  2. write(uio_fd, 1) 用于使能中断,使下一次可以收到中断信号;
  3. 每次 read() 后都需要进行 write(1)

3. 测试(关键)

3.1 如何计算 AXI GPIO 引脚号

在我创建的系统中,AXI-GPIO 的起始引脚号为 506(gpiochip506)。由于我使能了 AXI-GPIO 的两个通道,所以,我可以控制两个引脚,引脚号分别为 506 和 507,分别连接的是 PL_PS_Group0[0] 和 PL_PS_Group1[0]。

为什么起始引脚号是 506 呢?

mpsoc 中的 MIO 在系统中的起始引脚号是 332,而且,SOC 包含 78 个 MIO 引脚,96 个 EMIO 引脚。所以,AXI GPIO 的起始引脚为 332 + 78 + 96 = 506 .

3.2 如何获取中断对应 UIO 设备节点

设备树中包含了所有 PL 到 PS 的中断信息( 注意中断号要减去 32 ):

PL_PS_Group0[0:7] 对应 pl-ps-group0-1 ~ pl-ps-group0-8;

PL_PS_Group1[0:7] 对应 pl-ps-group1-1 ~ pl-ps-group1-8。

Linux 下可以通过 cat /sys/class/uio/uio0/name 获取 UIO 设备节点的名称,从而找到 /dev/ 下对应的 uio 文件。

也可以使用 lsuio 命令查看系统中的 UIO 设备节点信息:

Linux

3.3 如何产生中断信号

通过 PS 控制 AXI GPIO 输出高低电平使 PL 产生中断信号。

Linux

4. 总结

  1. ug1085 TRM 文档中的中断号减去 32 后再写入设备树中;
  2. 使用 fd = open() 打开 uio 设备节点后,read(fd) 用于等待中断,write(fd, 1) 用于使能中断。
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分