This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[FAQ] [参考译文] [常见问题解答] PROCESSOR-SDK:开始使用 AM62和 AM64系列处理器在 Linux 中使用 GPIO

Guru**** 2393975 points
Other Parts Discussed in Thread: SK-AM64B, SK-AM62-LP, TMDS62LEVM, AM62P, AM62L, SK-AM62B-P1, SK-AM62A-LP, SK-AM62P-LP, SYSCONFIG

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1494485/faq-processor-sdk-getting-started-with-gpios-in-linux-using-the-am62-and-am64-family-processors

器件型号:PROCESSOR-SDK-AM62X
主题中讨论的其他器件:AM62PAM62L、SK-AM64B、 SK-AM62B-P1、SK-AM62-LP SK-AM62A-LPSK-AM62P-LP、TMDS62LEVM SysConfig

工具与软件:

该常见问题解答的目标是让使用 TI EVM 的人员能够在 Linux 中使用 GPIO。 本指南将介绍如何在 Linux 器件树中设置 GPIO 以及如何在用户空间中对其进行切换。 本指南还将介绍一些可能遇到的常见问题。

这适用于适用于适用于 AM64x、AM62x、AM62A、AM62P、AM62L 的 Linux SDK 10.0+。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    通用文档链接:

    数据表:

    技术参考手册:

    各种 TI EVM 原理图:

    Linux SDK 文档:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我可以将哪些引脚用于 GPIO?

    这些信息在每个器件的各自数据表的"引脚属性"部分下进行了讨论。

    请注意、从"引脚属性"表中可以看到、其中许多引脚能够用于许多不同的功能。 在选择要使用的 GPIO 之前、请确保它不与要使用的另一个引脚功能发生冲突。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    使用 TI 评估模块(EVM)、我可以访问哪些 GPIO?

    TI EVM 具有在电路板(包括主域 GPIO 和一些 MCU GPIO)上暴露的 RPI 接头。 请参阅 TI EVM 的原理图、了解哪些引脚连接到 RPI 接头。

    请参阅常用链接以查看 EVM 产品页面、您可在其中找到原理图。

    RPI 接头通常标记为"用户扩展连接器"和"MCU 接头"。 下面是 SK-AM62B-P1的示例:

    有关哪些信号可以用作 GPIO、请参阅器件的数据表。 有些引脚标记了不同的功能、但仍可用作 GPIO。

    使用此信息选择要使用的 GPIO、然后可在 Linux 器件树中启用该信息。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在 Linux 中选择了 GPIO、如何在 Linux 器件树中启用 GPIO?

    要生成示例器件树代码、请参阅 SysConfig 工具: https://dev.ti.com/sysconfig/#/start

    启动工具后、只需选择器件并开始(使软件产品为空)。

    我们可以使用 SysConfig 工具的输出将其添加到 Linux 器件树中。 只需选择要使用的 GPIO 并下载右侧的.dtsi 输出。

    下面是一个非常简单的示例、用于在 AM62x 的 Linux 器件树中启用一些 GPIO 和 MCU GPIO:

    diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    index b1980b85c..6a34c9eeb 100644
    --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    @@ -186,6 +186,20 @@ AM62X_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (E14/E11) UART0_TXD */
            >;
        };
      
    +   main_gpio0_pins_default: main-gpio0-default-pins {
    +       pinctrl-single,pins = <
    +           AM62X_IOPAD(0x009c, PIN_INPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */
    +           AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */
    +       >;
    +   };
    +
    +   main_gpio1_pins_default: main-gpio1-default-pins {
    +       pinctrl-single,pins = <
    +           AM62X_IOPAD(0x01b4, PIN_INPUT, 7) /* (A13) SPI0_CS0.GPIO1_15 */
    +           AM62X_IOPAD(0x01d0, PIN_INPUT, 7) /* (A15) UART0_CTSn.GPIO1_22 */
    +       >;
    +   };
    +
        main_i2c0_pins_default: main-i2c0-pins-default {
            pinctrl-single,pins = <
                AM62X_IOPAD(0x1e0, PIN_INPUT_PULLUP, 0) /* (B16/E12) I2C0_SCL */
    @@ -329,6 +343,29 @@ AM62X_IOPAD(0x0078, PIN_OUTPUT, 1) /* (U24) GPMC0_AD15.VOUT0_DATA23 */
        };
     };
      
    +&mcu_pmx0 {
    +   mcugpio0_pins_default: mcugpio0-default-pins {
    +       pinctrl-single,pins = <
    +           AM62X_MCU_IOPAD(0x003c, PIN_INPUT, 7) /* (E5) MCU_MCAN1_TX.MCU_GPIO0_15 */
    +           AM62X_MCU_IOPAD(0x0040, PIN_INPUT, 7) /* (D4) MCU_MCAN1_RX.MCU_GPIO0_16 */
    +       >;
    +   };
    +};
    +
    +&main_gpio0 {
    +   status = "okay";
    +   pinctrl-names = "default";
    +   pinctrl-0 = <&main_gpio0_pins_default>;
    +   gpio-line-names ="","","","","","","","","","", //GPIO0_0->9
    +                    "","","","","","","","","","", //GPIO0_10->19
    +                    "","","","","","","","","","", //GPIO0_20->29
    +                    "","","","","","","","","TEST_GPIO0_38","", //GPIO0_30->39
    +                    "","","TEST_GPIO0_42","","","","","","",""; //GPIO0_40->49
    +};
    +
    +&main_gpio1 {
    +   status = "okay";
    +   pinctrl-names = "default";
    +   pinctrl-0 = <&main_gpio1_pins_default>;
    +   gpio-line-names ="","","","","","","","","","", //GPIO1_0->9
    +                    "","","","","","TEST_GPIO1_15","","","","", //GPIO1_10->19
    +                    "","","TEST_GPIO1_22","","","","","","","", //GPIO1_20->29
    +                    "","","","","","","","","","", //GPIO1_30->39
    +                    "","","","","","","","","",""; //GPIO1_40->49
    +};
    +
     &wkup_uart0 {
        /* WKUP UART0 is used by DM firmware */
        status = "reserved";
    @@ -578,11 +615,13 @@ dpi1_out: endpoint {
        };
     };
      
    -/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */
    +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage  */
     &mcu_gpio0 {
    -   status = "reserved";
    +   status = "okay";
    +   pinctrl-names = "default";
    +   pinctrl-0 = <&mcugpio0_pins_default>;
     };
      
     &mcu_gpio_intr {
    -   status = "reserved";
    +   status = "okay";
     };

    对于器件树、进行了两处更改: 在&MAIN_pmx0/&MCU_pmx0和参考节点下设置引脚多路复用器(&MAIN_GPIO0/&MAIN_GPIO1/&MCU_GPIO0)。 通常建议为 GPIO 添加名称以进行调试。

    如果您未使用 AM62x、请参阅引脚控制绑定以查看哪种绑定适用于您的器件: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/blame/arch/arm64/boot/dts/ti/k3-pinctrl.h?h=ti-linux-6.12.y

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    器件树已配置、如何编译为.dtb?

    请参考 Linux SDK 文档的常见链接。 按照说明将设备树源代码编译为.dtb。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    引导 Linux 后、如何控制用户空间中的 GPIO?

    配置、编译和加载器件树后、下一步是在 Linux 内核启动后控制用户空间中的 GPIO。 在 userspace 中、我们可以使用 GPIO sysfs (已弃用)或 libgpiod 命令集。 请注意、您只能使用其中一种 userspace 方法、而不能同时使用两种方法。

    Libgpiod

    在更高版本的 Linux SDK 中、建议使用 Libgpiod userspace 命令。 此工具集和 API 不是由 TI 编写的、因此请参阅 Github 存储库: https://github.com/brgl/libgpiod

    在默认的 Linux SDK 中会启用该功能、但如果需要、请参阅 menuconfig 条目:

    如示例器件树中所示、建议在器件树中添加"gpo-line-names"参数、因为这样可以简化用户空间中的 GPIO 调用。 有关启用 GPIO0_38的示例、请参阅下面的:

    root@am62xx-evm:~# gpioset TEST_GPIO0_38=1 #use ctrl + c to send an interrupt to end the command
    root@am62xx-evm:~# gpioset -z TEST_GPIO0_38=1 #add the -z flag to daemonize the command

    请注意在演示 GPIO 命令时、再次尝试更改 GPIO 将返回"器件或资源繁忙错误"、因此请终止现有命令的 PID。

    如果 GPIO 没有名称、请遵循 GPIO0_38的以下过程:

    root@am62xx-evm:~# gpiodetect #run gpiodetect to understand how gpio modules are assigned to chips
    gpiochip0 [600000.gpio] (92 lines)
    gpiochip1 [601000.gpio] (52 lines)
    gpiochip2 [1-0022] (24 lines)
    root@am62xx-evm:~# gpioset --unquoted -c 0 38=1 #use ctrl + c to send an interrupt to end the command, unquoted will not search for gpio line names.
    root@am62xx-evm:~# gpioset --unquoted -z -c 0 38=1 #add the -z flag to daemonize the command

    有关最新的命令、请参阅 GPIO 命令的手册页或使用--help 标志。

    有关在 Linux SDK 9.0及更早版本中使用 libgpiod 命令的示例、请参阅此常见问题解答: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1260373/faq-transitioning-the-gpio-userspace-interface-from-sysfs-to-chardev

    GPIO SYSFS

    正如文档 https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/admin-guide/gpio/sysfs.rst?h=ti-linux-6.6.y 中所述、GPIO SYSFS 已被弃用

    如果需要重新启用它、请参阅下面的内核配置:  

    更新内核配置后、请参阅 Linux 文档以编译内核映像。

    在本例中、将启用 GPIO0_38。 GPIO0的存储器映射地址为0x600000。

    root@am62xx-evm:~# cd /sys/class/gpio/
    root@am62xx-evm:/sys/class/gpio# ls -l
     
    total 0
    --w------- 1 root root 4096 Feb 24 04:51 export
    lrwxrwxrwx 1 root root    0 Feb 24 04:51 gpiochip287 -> ../../devices/platform/bus@f0000/20010000.i2c/i2c-1/1-0022/gpio/gpiochip287
    lrwxrwxrwx 1 root root    0 Feb 24 04:51 gpiochip311 -> ../../devices/platform/bus@f0000/601000.gpio/gpio/gpiochip311
    lrwxrwxrwx 1 root root    0 Feb 24 04:51 gpiochip399 -> ../../devices/platform/bus@f0000/600000.gpio/gpio/gpiochip399 #Use for GPIO0
    lrwxrwxrwx 1 root root    0 Feb 24 04:51 gpiochip486 -> ../../devices/platform/bus@f0000/bus@f0000:bus@4000000/4201000.gpio/gpio/gpiochip486
    lrwxrwxrwx 1 root root    0 Feb 24 04:51 gpiochip510 -> ../../devices/platform/bus@f0000/3b000000.memory-controller/gpio/gpiochip510
    --w------- 1 root root 4096 Feb 24 04:51 unexport
     
    root@am62xx-evm:/sys/class/gpio# echo 437 > export #GPIO0=399 + pin 38 = 437
    root@am62xx-evm:/sys/class/gpio# cd gpio437
    root@am62xx-evm:/sys/class/gpio/gpio437# echo out > direction
    root@am62xx-evm:/sys/class/gpio/gpio437# echo 1 > value

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在 Linux 中使用 GPIO 不起作用、有哪些调试步骤?

    首先、我们从 Linux SDK 中检查设置:

    • 确保器件树具有引脚多路复用器和基准节点。 如需示例、请参阅上面的示例器件树。
    • 确认用于 GPIO 的焊盘未被另一个模块使用。
    • 检查将设备树编译到 DTB 中是否未返回任何警告或错误。
    • 检查是否在 Linux 映像和模块中启用了所需的内核配置。
    • 确保使用正确的 dtb 文件和 Linux 映像来引导器件。

    Linux 正在引导时进行下一步检查:

    • Linux 正在引导时、检查引导日志、以防出现任何错误、警告或延迟探测。
      • 如果设备被延迟、请查看原因并尝试删除相关性。  

    启动 Linux 后、请检查以下各项:  

    • 可以检查"Cat /sys/kernel/debug/devices_deferred "、以了解在探测过程中哪些设备被推迟。
    • "Cat /sys/kernel/debug/gpio 将填充设备树中列出的所有 GPIO 名称。
    • "gpioinfo"还将填充器件树中列出的所有 GPIO 名称。
    • "gpiodetect"将填充 GPIO 模块列表。 确保列出的地址符合 TRM 的存储器映射寄存器列表中的要求且与之匹配。
    • 使用'devmem2 0x '以检查 PADCONFIG 寄存器、查看输入和输出缓冲器是否已启用。 请参阅数据表中的"引脚属性"表以查找地址。 然后、请参阅 TRM 的 PADCONFIG 寄存器部分、了解十六进制输出的含义。
    • 检查 GPIO 寄存器值。 请参阅有关 GPIO 外设和 GPIO 寄存器的 TRM 部分。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    常见问题

    下一部分将讨论一些常见问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

     GPIO0、GPIO1和 MCU_GPIO0之间有何差异?

    每个 SoC 被划分为不同的器件域、其中每个器件域连接到 SoC 的内核、并与特定的外设列表相集成。 有关设备域的更多信息、请参阅每个器件的技术参考手册(TRM)。

    主域将具有两个名为 GPIO0的 GPIO 模块、而 GPIO1和 MCU 域将具有一个名为 MCU_GPIO0的 GPIO 模块。 不同器件域中的每个 GPIO 功能相同。 它们在每个模块可能具有的 GPIO 数量上有所不同。

    要确定每个外设所具有的连续 GPIO 数量、请参阅器件树 GPIO 的"ti、ngpio"参数。 这可在" /board-support/ti-linux-kernel- /arch/arm64/boot/dts/ti/k3- -

    .dtsi'

    例如、对于 AM62x、请参阅以下内容:

    请注意、对于 AM62x、"ti、ngpio"参数值:主域的 GPIO0 = 92、主域的 GPIO1 = 52以及 MCU 域的 MCU_GPIO0 =24。

    有关"ti、ngpio"的更多信息、请参阅 Linux 设备树文档: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml?h=ti-linux-6.6.y#n53

    请注意、对于 AM62L、GPIO 模块是 GPIO0和 GPIO2。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    能否从 A53内核访问 MCU GPIO?

    一般而言、可以从包括 GPIO 在内的不同内核/器件域访问不同的外设。

    是的、运行 Linux 的 A53内核能够访问 MCU GPIO。 有关示例、请参阅此 E2E 常见问题解答: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1398198/faq-am62x-how-to-allocate-use-gpios-from-different-device-domains

    需要注意的是、当 Linux 声明 MCU 外设时、MCU 应用程序将无法访问相同的 GPIO。 有关更多信息、请参阅多核 Academy:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    "IOPAD"的作用是什么?

    第一个字段是 PADCONFIG 寄存器地址偏移量、它是器件 TRM 和数据表中定义的最后3个十六进制位。 这会告知 Linux 这些设置应用于哪个引脚。

    第二个字段控制输入/输出缓冲器、下一部分将对此进行讨论。 这不定义 GPIO 是否是输入/输出方向。

    第三个字段是焊盘的复用模式。 通常、GPIO 使用多路复用器模式7、但请参阅器件的数据表以了解完整信息。

    IOPAD 与 PADCONFIG 寄存器有何关系?  器件树的 pinmux 部分中的 PIN_INPUT 和 PIN_OUTPUT 是什么意思?

    在硬件层面上、对于 SoC 上的每个焊盘、都有一个 PADCONFIG 寄存器用于控制焊盘的设置。 有关更多信息、请参阅器件 TRM 中的焊盘配置寄存器部分。

    每个焊盘均用作收发器(位21)和接收器(位18)缓冲器、如下图所示。 通过在每个缓冲器上使用独立的使能信号、我们可以允许焊盘接收和/或发送。 这些缓冲器支持接收和发送数据。 SoC 上的大多数焊盘都是如此、但请参阅数据表了解完整信息。

    /resized-image/__size/320x240/__key/communityserver-discussions-components-files/791/pastedimage1730308931861v1.png

    那么 Linux 是如何配置硬件的呢?  请参阅定义引脚控制绑定的 k3-pinctrl.h: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/arch/arm64/boot/dts/ti/k3-pinctrl.h?h=ti-linux-6.6.y

    这些定义与"TRM 章节中名为"PAD 配置寄存器"的 PADCONFIG 寄存器位字段完全相同。 在 Linux 引导时、Linux 将使用 PIN_INPUT/PIN_OUTPUT 和任何其他参数来配置引脚。

    #define PULLUDEN_SHIFT      (16)
    #define PULLTYPESEL_SHIFT   (17)
    #define RXACTIVE_SHIFT      (18)
    #define DEBOUNCE_SHIFT      (11)
    #define WKUP_EN_SHIFT       (29)
     
    #define PULL_DISABLE        (1 << PULLUDEN_SHIFT)
    #define PULL_ENABLE     (0 << PULLUDEN_SHIFT)
     
    #define PULL_UP         (1 << PULLTYPESEL_SHIFT | PULL_ENABLE)
    #define PULL_DOWN       (0 << PULLTYPESEL_SHIFT | PULL_ENABLE)
     
    #define INPUT_EN        (1 << RXACTIVE_SHIFT)
    #define INPUT_DISABLE       (0 << RXACTIVE_SHIFT)
     
    /* Only these macros are expected be used directly in device tree files */
    #define PIN_OUTPUT      (INPUT_DISABLE | PULL_DISABLE)
    #define PIN_OUTPUT_PULLUP   (INPUT_DISABLE | PULL_UP)
    #define PIN_OUTPUT_PULLDOWN (INPUT_DISABLE | PULL_DOWN)
    #define PIN_INPUT       (INPUT_EN | PULL_DISABLE)
    #define PIN_INPUT_PULLUP    (INPUT_EN | PULL_UP)
    #define PIN_INPUT_PULLDOWN  (INPUT_EN | PULL_DOWN)

    请注意以下内容:

    • 输入仅受 RXACTIVE 影响(PADCONFIG 的第18位)
    • 输出 实际上不是如此 受 TX_DIS (PADCONFIG 的位21)影响、仅限 RXACTIVE

    这意味着在器件树中、PIN_INPUT 表示 两者可兼得 启用输入缓冲器和输出缓冲器。 PIN_OUTPUT 意味着只有输出缓冲器被启用并且输入缓冲器被禁用。 请记住、启用缓冲器可以实现在焊盘上进行接收和发送的功能。

    这也意味着配置 PIN_INPUT/PIN_OUTPUT 不会影响 GPIO 状态。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    GPIO 命令曾经在旧的 SDK 中工作、但在新的 SDK 中不工作。 问题是什么?

    GPIO SYSFS 已被弃用、因此它可能已从内核配置中删除。 可以在内核配置中重新启用它、如 GPIO 用户空间部分中所示。

    Libgpiod 是一个非 TI 编写的工具集和 API。 对于新的 SDK 版本、导入的 libgpiod 版本可能与之前的 SDK 不同。 有关最新的命令、请参阅 GPIO 命令的手册页或使用--help 标志。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    不同 Linux SDK 版本定义 gpiochip 的顺序不同。 为什么会这样?

    当 Linux 启动时、它会动态地将 gpiochips 分配给器件树中定义的 GPIO 模块。 对于不同的 Linux SDK 版本/Linux 内核版本、可能会存在新的依赖项、从而导致引导过程中的延迟探测。 这将改变 gpiochips 的枚举方式。 建议为 GPIO 分配名称、以便应用程序搜索 GPIO 的名称、而不是依靠 gpiochip 编号。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我希望在引导 Linux 时 GPIO 立即处于高电平/低电平。 如何在器件树中执行此操作?

    可以使用 GPIO-HOG 属性来执行此操作。 请参阅下面的一些示例:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我将编写一个使用 GPIO 的自定义应用程序。 从何处开始?

    首先、定制驱动程序和应用程序的支持非常有限、因为它超出了 E2E 论坛的范围。 我们只能对 Linux SDK 中提供的代码提供支持、因为它已由 TI 进行测试和验证。

    在移植到自定义应用之前、请确保 GPIO 可以在用户空间中正确使用。

    有关一些基本示例、请参阅 Libgpiod GitHub 页面: https://github.com/brgl/libgpiod/tree/master/examples

    有关使用传统接口的信息、请参阅其文档: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/driver-api/gpio/legacy.rst?h=ti-linux-6.6.y