【问题标题】:Programming GPIO pins on a FINTEK F81866A chipset在 FINTEK F81866A 芯片组上编程 GPIO 引脚
【发布时间】:2019-03-11 06:01:05
【问题描述】:

我有一台Cincoze DE-1000 工业PC,它配备Fintek F81866A 芯片组。我必须管理 DIO 引脚以读取物理按钮的输入并设置开/关 LED。我有 C++ 编程经验,但不是低/硬件级别的。

在PC随附的文档中,有如下C代码:

#define AddrPort 0x4E
#define DataPort 0x4F

//<Enter the Extended Function Mode>
WriteByte(AddrPort, 0x87)
WriteByte(AddrPort, 0x87) //Must write twice to entering Extended mode

//<Select Logic Device>
WriteByte(AddrPort, 0x07)
WriteByte(DataPort, 0x06)
//Select logic device 06h

//<Input Mode Selection> //Set GP74 to GP77 input mode
WriteByte(AddrPort, 0x80) //Select configuration register 80h
WriteByte(DataPort, 0x0X)
//Set (bit 4~7) = 0 to select GP 74~77 as Input mode.

//<input Value>
WriteByte(AddrPort, 0x82) // Select configuration register 82h
ReadByte(DataPort, Value) // Read bit 4~7(0xFx)= GP74 ~77 as High.

//<Leave the Extended Function Mode>
WriteByte(AddrPort, 0xAA)

据我了解,上面的代码应该读取四个输入 PIN 的值(因此每个 PIN 应该读取 1),但我真的很难理解它的实际工作原理。我已经理解逻辑(选择地址并读取/写入十六进制值),但我无法弄清楚WriteByte()ReadByte() 是哪种C 指令。另外,我不明白ReadByte(DataPort, Value) 行中的Value 来自哪里。它应该一起读取 4 个 PIN,所以它应该是某种“字节”类型,并且应该在其 4-7 位中包含 1,但我还是无法真正理解该行的含义。

我找到了answer for a similar chip,但对我的理解没有帮助。

请给我建议或指出一些相关文档。

【问题讨论】:

    标签: c gpio


    【解决方案1】:

    WriteByte()ReadByte() 不是 C 语言的一部分。从外观上看,它们是旨在作为操作系统内核端口 IO 的某种形式的系统调用的占位符的函数(不是按照此答案的先前版本直接执行内存映射 IO 的宏)。

    函数的原型大致如下:

    #include <stdint.h>
    void WriteByte(unsigned port, uint8_t value);
    void ReadByte(unsigned port, uint8_t *value);
    

    因此,Value 变量将是一个指向 8 位无符号整数的指针(也可以使用unsigned char),类似于:

    uint8_t realValue;
    uint8_t *Value = &realValue;
    

    当然,让Value 成为uint8_t 并拥有ReadByte(DataPort, &amp;Value) 会更有意义。但是示例代码也没有任何分号,所以可能从来没有实际运行过。无论哪种方式,这都是Value 包含您要查找的数据的方式。

    我还在这里找到了更多关于寄存器的文档 - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf

    希望这会有所帮助。

    【讨论】:

    • 您假设他正在访问的硬件正在使用 内存映射 I/O。如果您尝试在 Linux 或 Windows 等受保护模式操作系统上的用户空间应用程序中使用此代码,肯定会崩溃。
    • @JonathonReinhart 正确。我假设没有操作系统,但情况可能并非如此 WriteByte()ReadByte() 更有可能是函数,而 Value 是一个指针。
    • 关键是这些根本不是内存映射寄存器。它们是 I/O 端口,可通过 x86 上的单独指令访问。请参阅my answer above
    • @JonathonReinhart,谢谢,我看到了你的回答。但是 OP 询问 Value 变量来自哪里,因为它没有在示例代码中声明。我试图阐明这一点。
    • 你说得对,我对ReadByte的定义与OP的用法不兼容。
    【解决方案2】:

    该芯片看起来像一个相当典型的Super I/O controller,它基本上是将所有“慢速”外围设备组合到一个芯片组中的集线器。

    Coreboot 有一个关于 how to access the super I/O 的 wiki 页面。


    在 PC 架构上,端口 I/O 是使用特殊的 CPU 指令完成的,即 inout。这些是特权指令,只能从内核模式驱动程序(Ring 0)或已获得 I/O 特权的用户空间进程中使用。

    幸运的是,这在 Linux 中很容易。查看man page for outb and friends

    您使用 ioperm(2) 或 iopl(2) 来告诉内核允许用户空间应用程序访问有问题的 I/O 端口。否则将导致应用程序收到分段错误。

    所以我们可以将您的函数调整到这样的 Linux 环境中:

    /* Untested: Use at your own risk! */
    #include <sys/io.h>
    #include <stdio.h>
    
    #define ReadByte(port)          inb(port)
    #define WriteByte(port, val)    outb(val, port)
    
    int main(void)
    {
        if (iopl(3) < 0) {
            fprintf(stderr, "Failed to get I/O privileges (are you root?)\n");
            return 2;
        }
    
    
        /* Your code using ReadByte / WriteByte here */
    }
    

    警告

    在使用这种方法直接与超级 IO 通信时,您应该非常小心,因为您的操作系统几乎可以肯定有设备驱动程序与芯片通信。

    实现这一点的正确方法是编写一个与其他内核代码正确协调的设备驱动程序,以避免对设备的并发访问。

    Linux 内核提供了对至少一些 Super I/O 设备的 GPIO 访问;将其中之一移植到您的平台应该很简单。见this pull request for the IT87xx chipset

    【讨论】:

    • 您好乔纳森,感谢您的支持。我成功编译了代码,并且可以检测到物理按钮的按下。顺便说一句,我正在使用的平台是 Linux(Debian Stretch)。我理解您的警告:我的第一次尝试是使用 /sys/classgpio,但它经常失败。我尝试使用echo 74 &gt; /sys/class/gpio/export“激活”引脚(74 是文档中的数字,我什至尝试了 0 到 10000 之间的任何数字但没有成功)。我想不支持 Fintek 板。
    猜你喜欢
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    相关资源
    最近更新 更多