在 FINTEK F81866A 芯片组上编程 GPIO 引脚
Programming GPIO pins on a FINTEK F81866A chipset
我有一个 Cincoze DE-1000 industrial PC, that features a Fintek F81866A 芯片组。我必须管理 DIO 引脚以从物理按钮读取输入并设置 on/off 一个 LED。我有 C++ 编程经验,但不是 low/hardware 水平。
在 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),但我真的很难理解它是如何工作的。我已经理解了逻辑(选择一个地址和 reading/writing 一个十六进制值),但我无法弄清楚 WriteByte()
和 ReadByte()
是什么类型的 C 指令。另外,我不明白 ReadByte(DataPort, Value)
行中的 Value
是从哪里来的。它应该一起读取 4 个 PIN,所以它应该是某种 "byte" 类型,它的第 4-7 位应该包含 1,但我还是无法真正理解那一行的含义。
我找到了一个answer for a similar chip,但它并没有帮助我理解。
请给我建议或指出一些相关文档。
WriteByte()
和 ReadByte()
不是 C
语言的一部分。从表面上看,它们是函数,旨在作为 OS 内核端口 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, &Value)
会更有意义。但是示例代码也没有任何分号,所以可能从来没有真正 运行 的东西。无论哪种方式,这就是 Value
包含您要查找的数据的方式。
我还在此处找到了更多有关寄存器的文档 - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf
希望对您有所帮助。
该芯片看起来非常典型 Super I/O controller,它基本上是集线器,所有 "slow" 外围设备都组合到一个芯片组中。
Coreboot 有一个讨论 how to access the super I/O.
的 wiki 页面
在 PC 架构上,端口 I/O 是使用特殊的 CPU 指令完成的,即 in
和 out
。这些是特权指令,只能从内核模式驱动程序(Ring 0)或已获得 I/O 特权的用户空间进程中使用。
幸运的是,这在 Linux 中很容易。查看 man page for outb
and friends.
You use ioperm(2) or alternatively iopl(2) to tell the kernel to allow the user space application to access the I/O ports in question. Failure to do this will cause the application to receive a segmentation fault.
所以我们可以将您的函数调整到这样的 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 */
}
警告
使用此方法直接与 Super IO 对话时,您应该非常小心,因为您的操作系统几乎肯定有设备驱动程序也与芯片对话。
实现此目的的正确方法是编写一个与其他内核代码正确协调的设备驱动程序,以避免对设备的并发访问。
Linux 内核提供了对至少一些超级 I/O 设备的 GPIO 访问;将其中之一移植到您的平台应该很简单。参见 this pull request for the IT87xx chipset。
我有一个 Cincoze DE-1000 industrial PC, that features a Fintek F81866A 芯片组。我必须管理 DIO 引脚以从物理按钮读取输入并设置 on/off 一个 LED。我有 C++ 编程经验,但不是 low/hardware 水平。
在 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),但我真的很难理解它是如何工作的。我已经理解了逻辑(选择一个地址和 reading/writing 一个十六进制值),但我无法弄清楚 WriteByte()
和 ReadByte()
是什么类型的 C 指令。另外,我不明白 ReadByte(DataPort, Value)
行中的 Value
是从哪里来的。它应该一起读取 4 个 PIN,所以它应该是某种 "byte" 类型,它的第 4-7 位应该包含 1,但我还是无法真正理解那一行的含义。
我找到了一个answer for a similar chip,但它并没有帮助我理解。
请给我建议或指出一些相关文档。
WriteByte()
和 ReadByte()
不是 C
语言的一部分。从表面上看,它们是函数,旨在作为 OS 内核端口 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, &Value)
会更有意义。但是示例代码也没有任何分号,所以可能从来没有真正 运行 的东西。无论哪种方式,这就是 Value
包含您要查找的数据的方式。
我还在此处找到了更多有关寄存器的文档 - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf
希望对您有所帮助。
该芯片看起来非常典型 Super I/O controller,它基本上是集线器,所有 "slow" 外围设备都组合到一个芯片组中。
Coreboot 有一个讨论 how to access the super I/O.
的 wiki 页面在 PC 架构上,端口 I/O 是使用特殊的 CPU 指令完成的,即 in
和 out
。这些是特权指令,只能从内核模式驱动程序(Ring 0)或已获得 I/O 特权的用户空间进程中使用。
幸运的是,这在 Linux 中很容易。查看 man page for outb
and friends.
You use ioperm(2) or alternatively iopl(2) to tell the kernel to allow the user space application to access the I/O ports in question. Failure to do this will cause the application to receive a segmentation fault.
所以我们可以将您的函数调整到这样的 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 */
}
警告
使用此方法直接与 Super IO 对话时,您应该非常小心,因为您的操作系统几乎肯定有设备驱动程序也与芯片对话。
实现此目的的正确方法是编写一个与其他内核代码正确协调的设备驱动程序,以避免对设备的并发访问。
Linux 内核提供了对至少一些超级 I/O 设备的 GPIO 访问;将其中之一移植到您的平台应该很简单。参见 this pull request for the IT87xx chipset。