电子发烧友App

硬声App

0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示
电子发烧友网>电子资料下载>电子资料>使用Genode控制Zybo Z7 GPIO

使用Genode控制Zybo Z7 GPIO

2023-06-13 | zip | 0.00 MB | 次下载 | 免费

资料介绍

描述

Zybo Z7 带有一组用户控制的 LED、按钮和开关。所有这些都可以通过 Zynq 的 GPIO 控制器访问。然而,只有一个 LED 和两个按钮直接连接到处理系统 (PS),其余连接到可编程逻辑 (PL)。因此,在这个项目中,我不仅会展示如何控制 Zynq 的 GPIO,还会展示如何使用 GPIO 和 MMIO 与 PL 交互。

请注意,我假设您知道如何在 Zybo Z7 上运行 Genode。如果没有,请查看我的Zybo Z7 项目入门

建筑学

下图说明了 Genode 中用于引脚级访问的一般架构。最底层是Core / Init组件,它拥有最终权限并且不受访问策略限制。它只是通过 IRQ 和 MMIO 服务向平台驱动程序提供所有设备资源的权限后者提供平台服务,特定组件可以通过该服务获得对单个设备的授权。在这种情况下,引脚驱动程序获得对 GPIO 控制器的权限。同样,它提供了Pin control Pin stateIRQ服务,用于将各个引脚的写入、读取和通知权限传递给特定组件。在此示例中,我将实现一个 MIO 演示组件,该组件控制 Zybo Z7 板的按钮 4、按钮 5 和 LED 4 的 PS 可访问 GPIO 引脚。

pYYBAGSAaEqAZ04CAAB1bJajeQ4670.png
权限由平台驱动和管脚驱动逐渐降低。
 

测试引脚驱动器

Genode 21.11 引入了Pin I/O 会话接口,该接口首先由A64 SoC 的引脚驱动程序实现使用 A64 引脚驱动程序作为蓝图,我效仿并为 Zynq SoC 实现了引脚驱动程序。由于出色的基础工作,我能够重用大部分代码并专注于特定于 SoC 的部分。

有了手边的引脚驱动器,我已经能够控制 PS 可访问的 LED 和按钮。因此,我编写了一个微型 MIO 演示组件。按下按钮 4 时组件应打开 LED,按下按钮 5 时关闭 LED。它还会生成反映 LED 状态的状态报告。

编写组件的第一步是创建一个target.mk文件。惯例是根据组件的类型将组件的源代码放在src/app、src/server、src/driverssrc/test 的子目录中。在我的genode-zynq 存储库的克隆中,我因此创建了包含以下内容的文件src/app/zynq_gpio_demo/mio/target.mk 。请注意,因为我要实现多个相关组件,所以我将所有组件捆绑在一个公共子目录zynq_gpio_demo 中。

TARGET := zybo_gpio_demo_mio
SRC_CC := main.cc
LIBS   := base

target.mk包含一些声明,这些声明将在编译组件时由Genode构建系统解释。第一行指定目标二进制文件的名称。第二行说明应将哪些源文件传递给 C++ 编译器。在第三行中,我定义了库依赖项(表示 Genode 的基础 API)。base

接下来,我创建了main.cc文件。让我们从前几行开始。

/* Genode includes */
#include 
#include #include #include #include namespace Demo { using namespace Genode; struct Main; } /* [...] see below */ void Component::construct(Genode::Env &env) { static Demo::Main main(env); }

我们必须包含一些头文件:base/component.h头文件是实现本机 Genode 组件所必需的。接下来的三个包含是前面提到的由引脚驱动程序实现的引脚 I/O 会话接口所必需的。最后,os/reporter.h需要生成上述状态报告。

我进一步Main在单独的Demo名称空间中声明了一个对象。本地 Genode 组件没有作为main() 我们在 POSIX 程序中使用的入口点的功能。相反,入口点是Component::construct() 我简单地按Demo::Main对象实例化的方法。现在,让我们看一下它的实现。

struct Demo::Main
{
    /* members */

    Env &_env;

    Pin_state::Connection   _btn4 { _env, "Btn4" };
    Pin_state::Connection   _btn5 { _env, "Btn5" };

    Pin_control::Connection _led4 { _env, "Led4" };

    Irq_connection _irq4 { _env, "Btn4" };
    Irq_connection _irq5 { _env, "Btn5" };

    Signal_handler _irq_handler {
        _env.ep(), *this, &Main::_handle_irq };

    Expanding_reporter _reporter { _env, "state", "state" };


    /* methods */

    void _update_state(bool on)
    {
        _reporter.generate([&] (Genode::Xml_generator & xml) {
            xml.attribute("value", on ? "yes" : "no");
        });

        _led4.state(on);
    }

    void _handle_irq()
    {
        _irq4.ack_irq();
        _irq5.ack_irq();

        if (_btn4.state())
            _update_state(true);
        else if (_btn5.state())
            _update_state(false);
    }


    /* constructor */

    Main(Env &env) : _env(env)
    {
        _update_state(false);

        _irq4.sigh(_irq_handler);
        _irq5.sigh(_irq_handler);
        _irq4.ack_irq();
        _irq5.ack_irq();
    }
};

成员:首先,该Main对象持有一个引用,Genode::Env因为这是构建其他成员所必需的。为了访问按钮的输入引脚,我使用了Pin_state::Connection对象。传递给其构造函数的字符串称为会话标签,由 pin 驱动程序评估以应用匹配的访问控制策略(详情如下)。同样,为了访问 LED 的输出引脚,我使用了一个Pin_control::Connection对象。此外,因为我想收到按钮状态更改的通知,所以我Irq_connection为每个按钮添加了一个对象。这些伴随着一个Signal_handler将注册到 IRQ 连接的对象。信号处理程序将调用该方法。最后,我正在使用状态报告。_handle_irq()Expanding_reporterExpanding_reporter将两个字符串作为构造函数参数。第一个字符串指定顶级 XML 节点的名称(Genode 中的报告通常是 XML 格式的),而第二个字符串定义会话标签,可以将其视为报告的名称。

方法:_update_state() 方法有助于设置 LED 的状态和更新组件的状态报告。只要任一按钮出现 IRQ,信号处理程序就会调用该方法。_handle_irq()此方法确认 IRQ 并评估按钮状态以相应地更新 LED 状态。

构造函数:构造函数非常简单。它设置初始 LED 状态,在两个 IRQ 连接上注册信号处理程序并确认任何挂起的 IRQ。

我们需要的下一个要素是运行脚本。在 Genode 中,运行脚本是对某个要执行的场景的定义。更准确地说,它包含有关要构建的组件以及如何组合它们以创建特定场景的信息运行脚本还可以评估正在运行的系统的(串行)输出以检查错误。由于运行脚本位于run/目录中,因此我在 genode-zynq 存储库的克隆中创建了包含以下内容的文件run/zynq_gpio_demo.run 。

create_boot_directory

 import_from_depot [depot_user]/src/[base_src] \
                   [depot_user]/src/init \
                   [depot_user]/src/report_rom \
                   [depot_user]/src/zynq_platform_drv \
                   [depot_user]/src/zynq_pin_drv \
                   [depot_user]/raw/[board]-devices

 build { app/zybo_gpio_demo }

 install_config {
     <config>
         <parent-provides>
             <service name="LOG"/>
             <service name="PD"/>
             <service name="CPU"/>
             <service name="ROM"/>
             <service name="IO_MEM"/>
             <service name="IRQ"/>
         parent-provides>

         <default caps="200"/>

         <start name="report_rom">
             <resource name="RAM" quantum="1M"/>
             <provides>
                 <service name="Report"/>
                 <service name="ROM"/>
             provides>
             <route>
                 <service name="ROM"> <parent/> service>
                 <service name="CPU"> <parent/> service>
                 <service name="PD">  <parent/> service>
                 <service name="LOG"> <parent/> service>
             route>
             <config verbose="yes"/>
         start>

         <start name="platform_drv" managing_system="yes">
             <binary name="zynq_platform_drv"/>
             <resource name="RAM" quantum="1M"/>
             <provides><service name="Platform"/>provides>
             <config>
                 <policy label="zynq_pin_drv -> ">
                     <device name="gpio0"/>
                 policy>
             config>
             <route>
                 <any-service> <parent/> any-service>
             route>
         start>

         <start name="zynq_pin_drv">
             <resource name="RAM" quantum="1M"/>
             <provides>
                 <service name="Pin_state"/>
                 <service name="Pin_control"/>
                 <service name="IRQ"/>
             provides>
             <route>
                 <service name="ROM"> <parent/> service>
                 <service name="CPU"> <parent/> service>
                 <service name="PD">  <parent/> service>
                 <service name="LOG"> <parent/> service>
                 <service name="Platform">
                     <child name="platform_drv"/>
                 service>
             route>
             <config>
                <in  name="Btn4" bank="1" index="18" irq="rising"/>
                <in  name="Btn5" bank="1" index="19" irq="rising"/>
                <out name="Led4" bank="0" index="7"  default="on"/>

                <policy label_prefix="zybo_gpio_demo_mio -> Btn4" pin="Btn4"/>
                <policy label_prefix="zybo_gpio_demo_mio -> Btn5" pin="Btn5"/>
                <policy label_prefix="zybo_gpio_demo_mio -> Led4" pin="Led4"/>
             config>
         start>

         <start name="zybo_gpio_demo_mio">
             <resource name="RAM" quantum="1M"/>
             <route>
                 <service name="Pin_control">
                     <child name="zynq_pin_drv"/>
                 service>
                 <service name="Pin_state"> 
                     <child name="zynq_pin_drv"/>
                 service>
                 <service name="IRQ">
                     <child name="zynq_pin_drv"/>
                 service>
                 <service name="report">
                     <child name="report_rom"/>
                 service>
                 <service name="ROM"> <parent/> service>
                 <service name="CPU"> <parent/> service>
                 <service name="PD">  <parent/> service>
                 <service name="LOG"> <parent/> service>
             route>
             <config/>
         start>

     config>
 }

 build_boot_image { zybo_gpio_demo_mio }

 run_genode_until forever

我不想在这里详述所有细节。运行脚本指定要从仓库(Genode 的包管理)导入哪些档案,以及要从源代码树构建哪些组件。它还为顶级 init 组件安装配置。关于init的配置的详细解释请参考Genode手册的系统配置章节。但是,我们可以在没有深入了解的情况下确定该场景由四个部分组成:report_romplatform_drvzynq_pin_drvzybo_gpio_demo_mio

report_rom该组件提供一个ROM和一个Report服务。它允许组件发布它们的报告,这些报告可以通过 ROM 连接访问。因此,它实现了单写入器、多读取器方案。

platform_drv这是一个驱动程序组件,可以最终控制硬件外围设备(例如 MMIO 设备)。根据其配置,它通过提供的平台服务将对各个设备的控制权传递给其他组件。平台驱动程序需要访问我从软件仓库导入的板特定设备ROM。它的配置包含基于标签的策略,这些策略将设备(由设备ROM定义)分配给相应的平台会话。在这里,被授予对设备的访问权限zynq_pin_drvgpio0

zynq_pin_drv:这是引脚驱动程序。其配置为按钮指定了两个输入引脚,为 LED 指定了一个输出引脚。查看Zybo Z7 手册,我发现 LED 4 连接到 MIO 引脚 7,按钮 4 和 5 分别连接到 MIO 引脚 50 和 51。知道 GPIO bank 0 覆盖 MIO 引脚 0 到 31 而 bank 1 覆盖引脚 32 到 53,我最终得到了发布的配置。与平台驱动程序类似,对单个引脚的访问由基于标签的策略定义。

zybo_gpio_demo_mio:这是我上面实现的演示组件。请注意,我将它的Pin_state会话请求路由到 pin 驱动程序。会话请求被路由到组件。Pin_controlIrqreportreport_rom

该场景的构建和运行如下:

build/arm_v7a$ make run/zybo_gpio_demo BOARD=zynq_zybo_z7 KERNEL=hw

通过此设置,我可以使用两个按钮打开/关闭 LED。在串行控制台上,我可以进一步看到以下输出:

[init -> report_rom] report 'zybo_gpio_demo_mio -> state'
[init -> report_rom]   
[init -> report_rom] report 'zybo_gpio_demo_mio -> state'
[init -> report_rom]   "yes"/>

并不壮观,但看到引脚驱动器工作时仍然令人满意。在下一步中,我为 FPGA 创建了一个自定义比特流来控制连接到 PL 的开关、按钮和 LED。

创建自定义比特流

为可编程逻辑实施复杂的定制设计可能会很繁琐,尤其是如果您是 FPGA 领域的新手。我最后一次使用赛灵思 FPGA 是在大约十年前,当时工具发生了很大变化。因此,我从一个非常简单的设计开始,以检查我的基本设置是否正确。

作为先决条件,我必须在单独的 Ubuntu VM 中安装 Vivado ML Standard。我对它占用的磁盘空间量 (~60GB) 感到震惊,因此不得不相应地增加 VM 大小。

作为起点,我遵循了教程由于它已经包含了 Vivado 的详细分步说明,因此我宁愿坚持对本文中的各个步骤进行简要总结。

在 Vivado 中,我打开了一个新项目并使用左侧的 Flow Navigator 创建了一个模块设计。在block design中,我添加了Zynq处理系统作为IP(intellectual property)核。添加 IP 核后,Vivado 通常会提供运行连接自动化以连接所有明显信号的选项。运行自动化将IP 核的接口DDR和接口连接到相应的(自动创建的)外部端口FIXED_IO

在这一点上,我很好奇我的最低限度但无用的设计是否基本上是完整和正确的,因此点击了“验证设计”按钮。

poYBAGSAaEyAWTHrAAAb0WElVYI512.png
 

哎呀!显然,因为我没有按照上述教程的建议添加 AXI IP 核,连接自动化无法决定如何连接 AXI 时钟信号。通过锁定教程中的其他步骤,我能够决定 AXI 时钟信号应该连接到FCLK_CLK0IP 内核的接口。

修复此问题后,我生成了 HD​​L 包装器(右键单击模块设计)。不幸的是,我的 Vivado 安装在此过程中总是卡住,就像“初始化语言服务器”时一样。工具设置工具设置文本编辑器→语法检查中将语法检查从“Sigasi”更改为“Vivado”,在重新启动 Vivado 后为我解决了这个问题。

在这一点上,我开始偏离上述教程。我不想实例化 AXI_GPIO IP 内核(这需要引脚驱动程序的支持),而是想使用 SoC 的 GPIO 控制器与 PL 交互。这是可能的,因为 GPIO 控制器的 bank 2 和 3 通过 EMIO 接口连接到 PL。EMIO 信号只需要路由到 FPGA 的正确引脚。

通过双击 Zynq PS IP 内核,我在外设 I/O 引脚卡上启用了 GPIO EMIO。此外,在MIO 配置卡上,我将 EMIO GPIO 宽度设置为 12(用于 4 个开关、4 个 LED、4 个按钮)。通过这样做,IP 内核获得了一个GPIO_0接口。为了使它成为一个外部信号,我选择了名称并右击以从上下文菜单中选择Make external 。这创建了一个名为连接到 IP 内核的外部接口。GPIO_0_0由于 GPIO 信号是三态的,外部信号将由gpio_0_0_tri_ioVivado 命名。我通过查看 HDL 包装器(在重新生成它之后)仔细检查了这个命名方案。

最后,我添加了一个 Xilinx 设计约束 (XDC) 文件以将信号绑定gpio_0_0_tri_io 到那些实际连接到开关/LED/按钮的设备引脚。幸运的是,Digilent为其电路板提供了主文件。使用主文件,只需取消注释个别行并插入相应的信号名称。我通过添加源对话框添加了 Zybo-Z7-Master 文件,取消了 LED、按钮和开关行的注释,并将信号名称插入gpio_0_0_tri_io[0]gpio_0_0_tri_io[11]. 您可以在上述教程中找到更详细的说明。

生成比特流时,我注意到 Vivado 占用了大量 RAM。由于我在单独的 Ubuntu VM 中运行该工具,这有时会导致无法解释的构建错误。向 VM 添加另一个 GB 的 RAM 并将作业数量减少到 1 对我来说是个窍门。最终,我能够通过File Export Export Bitstream File导出生成的比特流文件

在启动时加载比特流

由于 FPGA 使用易失性存储器来存储其编程,因此必须在每次通电后重新编程。比特流文件包含必要的(特定于设备的)信息。最简单的方法是让引导加载程序负责加载比特流。Xilinx 的 FSBL 和 u-boot 对此提供支持。当使用相应的配置选项编译时,您可以使用 u-boot 的fpga命令加载比特流。有两个子命令:loadloadb前者需要原始比特流 (.bin),例如通过回读获取的比特流。后者需要 Vivado 导出的 a.bit 文件。与原始比特流相比,此文件具有不同的字节顺序并包含文件头。

为了简化启动时的比特流加载,我在 u-boot 的默认环境中添加了两个命令,分别检查fpga.bin fpga.bit文件,如果存在,fpga在启动到 Genode 之前执行相应的命令。此外,您可以通过将以下行添加到您的etc/build.conf来使用比特流填充 SD 卡映像

RUN_OPT_zybo += --image-uboot-bitstream "/path/to/bitstream.bit"

测试比特流

为了测试比特流,我实现了一个zybo_gpio_demo_sw组件,它控制开关和每个开关旁边的 LED。代码非常简单。您可以在genode-zynq 存储库中找到它

我还在run/zybo_gpio_demo.run脚本中添加了以下启动节点

<start name="zybo_gpio_demo_sw">
     <resource name="RAM" quantum="1M"/>
     <route>
         <service name="Pin_control"><child name="zynq_pin_drv"/> service>
         <service name="Pin_state">  <child name="zynq_pin_drv"/> service>
         <service name="IRQ">        <child name="zynq_pin_drv"/> service>
         <service name="ROM"> <parent/> service>
         <service name="CPU"> <parent/> service>
         <service name="PD">  <parent/> service>
         <service name="LOG"> <parent/> service>
     route>
     <config/>
 start>

此外,更有趣的是,我修改了 pin-driver 配置以添加相应的策略:

<config>
     
     <in  name="Btn4" bank="1" index="18" irq="rising"/>
     <in  name="Btn5" bank="1" index="19" irq="rising"/>
     <out name="Led4" bank="0" index="7"  default="on"/>

     <policy label="zybo_gpio_demo_mio -> Btn4" pin="Btn4"/>
     <policy label="zybo_gpio_demo_mio -> Btn5" pin="Btn5"/>
     <policy label="zybo_gpio_demo_mio -> Led4" pin="Led4"/>

     
     <in  name="Sw0"  bank="2" index="0" irq="edges"/>
     <in  name="Sw1"  bank="2" index="1" irq="edges"/>
     <in  name="Sw2"  bank="2" index="2" irq="edges"/>
     <in  name="Sw3"  bank="2" index="3" irq="edges"/>
     <out name="Led0" bank="2" index="8"  default="off"/>
     <out name="Led1" bank="2" index="9"  default="off"/>
     <out name="Led2" bank="2" index="10" default="off"/>
     <out name="Led3" bank="2" index="11" default="off"/>

     <policy label="zybo_gpio_demo_sw -> Sw0"  pin="Sw0"/>
     <policy label="zybo_gpio_demo_sw -> Sw1"  pin="Sw1"/>
     <policy label="zybo_gpio_demo_sw -> Sw2"  pin="Sw2"/>
     <policy label="zybo_gpio_demo_sw -> Sw3"  pin="Sw3"/>
     <policy label="zybo_gpio_demo_sw -> Led0" pin="Led0"/>
     <policy label="zybo_gpio_demo_sw -> Led1" pin="Led1"/>
     <policy label="zybo_gpio_demo_sw -> Led2" pin="Led2"/>
     <policy label="zybo_gpio_demo_sw -> Led3" pin="Led3"/>
 config>

因为我想在上升沿和下降沿触发中断,所以我使用了开关输入引脚。irq="edges"

启用 RGB LED

到目前为止,我故意忽略了 Zybo Z7-20 (Z7-10) 上两个(一个)RGB LED 的存在。其中每一个实际上都由一个绿色、一个蓝色和一个红色 LED 组成。原则上,这些 LED 可以像其他 LED 一样进行控制。然而,由于它们的亮度需要通过脉宽调制 (PWM) 进行调节,因此为这项工作实施定制 IP 内核更为明智。这在本故事的第 2 部分中有所介绍,其中还包括使用我的预构建比特流再现完整 GPIO 演示的说明。


下载该资料的人也在下载 下载该资料的人还在阅读
更多 >

评论

查看更多

下载排行

本周

  1. 1山景DSP芯片AP8248A2数据手册
  2. 1.06 MB  |  532次下载  |  免费
  3. 2RK3399完整板原理图(支持平板,盒子VR)
  4. 3.28 MB  |  339次下载  |  免费
  5. 3TC358743XBG评估板参考手册
  6. 1.36 MB  |  330次下载  |  免费
  7. 4DFM软件使用教程
  8. 0.84 MB  |  295次下载  |  免费
  9. 5元宇宙深度解析—未来的未来-风口还是泡沫
  10. 6.40 MB  |  227次下载  |  免费
  11. 6迪文DGUS开发指南
  12. 31.67 MB  |  194次下载  |  免费
  13. 7元宇宙底层硬件系列报告
  14. 13.42 MB  |  182次下载  |  免费
  15. 8FP5207XR-G1中文应用手册
  16. 1.09 MB  |  178次下载  |  免费

本月

  1. 1OrCAD10.5下载OrCAD10.5中文版软件
  2. 0.00 MB  |  234315次下载  |  免费
  3. 2555集成电路应用800例(新编版)
  4. 0.00 MB  |  33566次下载  |  免费
  5. 3接口电路图大全
  6. 未知  |  30323次下载  |  免费
  7. 4开关电源设计实例指南
  8. 未知  |  21549次下载  |  免费
  9. 5电气工程师手册免费下载(新编第二版pdf电子书)
  10. 0.00 MB  |  15349次下载  |  免费
  11. 6数字电路基础pdf(下载)
  12. 未知  |  13750次下载  |  免费
  13. 7电子制作实例集锦 下载
  14. 未知  |  8113次下载  |  免费
  15. 8《LED驱动电路设计》 温德尔著
  16. 0.00 MB  |  6656次下载  |  免费

总榜

  1. 1matlab软件下载入口
  2. 未知  |  935054次下载  |  免费
  3. 2protel99se软件下载(可英文版转中文版)
  4. 78.1 MB  |  537798次下载  |  免费
  5. 3MATLAB 7.1 下载 (含软件介绍)
  6. 未知  |  420027次下载  |  免费
  7. 4OrCAD10.5下载OrCAD10.5中文版软件
  8. 0.00 MB  |  234315次下载  |  免费
  9. 5Altium DXP2002下载入口
  10. 未知  |  233046次下载  |  免费
  11. 6电路仿真软件multisim 10.0免费下载
  12. 340992  |  191187次下载  |  免费
  13. 7十天学会AVR单片机与C语言视频教程 下载
  14. 158M  |  183279次下载  |  免费
  15. 8proe5.0野火版下载(中文版免费下载)
  16. 未知  |  138040次下载  |  免费