我有一台Cincoze DE-1000工业PC,它具有Fintek F81866A芯片组。我必须管理DIO引脚以从一个物理按钮读取输入并设置LED的开/关。我有C ++编程经验,但没有较低/硬件级别的经验。
在PC随附的文档中,有以下C代码:
User.aggregate([{
"$lookup":{
"from":"projects",
"let":{"projects":"$projects","user":"$_id"},
"pipeline":[
{"$match":{
"$expr":{
"$and":[
{"$in":["$_id","$$projects"]},
{"$in":["$$user","$user"]}
]
}}
},
{"$lookup":{
"from":"tasks",
"localField":"tasks",
"foreignField":"_id",
"as":"tasks"
}}
],
"as":"project-tasks"
}
}])
据我了解,上面的代码应该读取四个输入PIN的值(因此每个PIN应该读取1),但是我真的很难理解它的实际工作原理。我已经了解了逻辑(选择地址并向其读取/写入十六进制值),但是我无法弄清楚#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)
和WriteByte()
是哪种C指令。另外,我不知道ReadByte()
行中Value
的来源。它应该一起读取4个PIN,因此应该是某种“字节”类型,并且在其4-7位中应包含1,但是我仍然无法真正理解该行的含义。
我找到了answer for a similar chip,但是它对我的理解没有帮助。
请给我建议或指向一些相关文档。
答案 0 :(得分:4)
该芯片看起来像一个非常典型的Super I/O controller,基本上是所有“慢速”外围设备都组合成单个芯片组的枢纽。
Coreboot的Wiki页面谈论how to access the super I/O。
在PC架构上,端口I / O 使用特殊的CPU指令in
和out
完成。这些是特权指令,只能从内核模式驱动程序(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 */
}
使用这种方法直接与Super IO对话时应非常小心,因为您的操作系统几乎可以肯定也有与晶片对话的设备驱动程序。
正确的实现方法是编写一个设备驱动程序,该设备驱动程序应与其他内核代码正确协调,以避免并发访问设备。
Linux内核提供了对至少某些超级I / O设备的GPIO访问;将其中之一移植到您的平台应该很简单。参见this pull request for the IT87xx chipset。
答案 1 :(得分:2)
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
希望这会有所帮助。