問題描述
Intel 芯片組 ‑ GPIO 編程 (Intel chipset ‑ GPIO programming)
從規範中,我知道了以下信息:
JGPIO1 PIN# :10
SoC GPIO # : 71
USE select: IO 0x532[7] ( 0 = native function, 1 = GPIO )
IO select: IO 0x536[7] (0 = output, 1 = input )
Level: IO 0x540[7] ( 0 = low, 1= high )
在這種情況下,我想對 GPIO 引腳 #10 進行編程。有任何示例或示例代碼可以參考嗎?
我可以通過 RW‑everything [1] 做到這一點。但是,這是在 Windows 中。
我想在 C 和 linux 環境中執行此操作。
請指教。
============================================ ====================
比如我想設置
0x532處的第7位為1
第 7 位在 0x536 處為 0
第 7 位在 0x540 處為 1。
參考解法
方法 1:
In Linux userspace the typical method used to access GPIOs is the through the /sys pseudo‑filesystem (aka sysfs). This offers a somewhat‑portable interface that tries to minimize hardware dependencies and avoid conflicts with device drivers.
To determine the GPIO numbers that you want to access on your board, you will have to consult your SoC documentation. The directory names in /sys/class/gpio/ need to be identified with their hardware register counterparts. These directory names will have the form gpiochipN, where N is for the base GPIO number in that register. The file gpiochipN/label should help identify the register, e.g. by its (memory or port) address.
Note that N may not start with 0. An Intel BayTrail system might have gpiochip82 as its first directory, so the lowest‑numbered GPIO would be 82. The bit number of the register should be added to the base number to obtain the GPIO number.
Refer to Sysfs Interface for Userspace for formal documentation.
I can do this thorugh RW‑everything 1. However, this is in Windows.
A similar program could probably be written to execute under Linux. However Linux programs (unlike Windows which is x86‑centric) should be portable to other architectures, so such a program that needs to know low‑level hardware details is near‑impossible to write/maintain. One purpose of device drivers is to isolate/modularize such HW details, and such a program is trying to circumvent those drivers!
Additionally using such a program could make a system unstable or malfunction. Mucking around memory and/or device registers is unsafe on a running system. FWIW I have written a utility that reports the configuration of the pins for one specific SoC, but that only reads the registers and never modifies any setting.
Note that most SoC documentation (as well as Linux) treat pin control and configuration as a separate (but closely related if not overlapping) subsystem to GPIOs. Pin control and configuration typically includes:
- multiplexing the pin for different peripherals/functionality,
- directionality (i.e. input or output),
- connecting pull‑up or pull‑down resistors,
- input filtering (i.e. de‑glitching),
- output drive (e.g. open drain), and
- interrupt control.
The GPIO subsystem typically handles:
- directionality,
- pin state, and
- interrupt control.
方法 2:
Many embedded boards come with support for the EAPI Library ‑ "Embedded Application Programming Interface". The base spec was developed by the PICMG. Here's the doc.
If you want to control and/or detect GPIO pins from a user‑space program, this API probably gives you the easiest and quickest solution.
Here's a code fragment using EAPI to turn on/off an arbitrary GPO pin. (pin numbering on the device itself usually doesn't match the pin numbers on the header connector on your board so you need to translate "external" vs "internal" pin numbers.
bool
DvmA44I2CGPI::setOutput(int pinNum, bool pinOn)
{
if (pinNum > NUMPINS)
return false;
bool pinPhyVal = (mReversePolarity) ? !pinOn : pinOn;
uint32_t val = (pinPhyVal) ? EAPI_GPIO_HIGH : EAPI_GPIO_LOW;
uint32_t inputs, outputs;
EApiStatus_t rc;
if ((rc = EApiGPIOGetDirectionCaps(EAPI_ID_GPIO_BANK00, &inputs, &outputs)) != EAPI_STATUS_SUCCESS)
{
fprintf(stderr, "EApiGPIOGetDirectionCaps() Get Direction Failed: ");
printStatus(rc);
return false;
}
if ((rc = EApiGPIOSetLevel(mPinMap[pinNum‑1], outputs, val)) != EAPI_STATUS_SUCCESS)
{
fprintf(stderr, "EApiGPIOSetLevel() Set Level Failed: ");
printStatus(rc);
return false;
}
return true;
}
(by user3815726、sawdust、Danny)