对linux c app里面的一个gpio操作云里雾里半天,是时候好好理理了。
主要是这gpio number是如何同pin number 一一对应的。
256
root@mxj-zbcs-310:#tree /sys/class/gpio
.
|-- export
|-- gpio120 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio120
|-- gpio228 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio228
|-- gpio229 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio229
|-- gpio232 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio232
|-- gpio32 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio32
|-- gpio33 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio33
|-- gpio359 -> ../../devices/soc.0/1f02c00.pinctrl/gpio/gpio359
|-- gpio64 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpio64
|-- gpiochip0 -> ../../devices/soc.0/1c20800.pinctrl/gpio/gpiochip0
|-- gpiochip1024 -> ../../devices/soc.0/pinctrl.1/gpio/gpiochip1024
|-- gpiochip352 -> ../../devices/soc.0/1f02c00.pinctrl/gpio/gpiochip352
`-- unexport
奇怪,今天发现sys/class/gpio
下面的gpio没有了。只剩下gpiochip
了。原来需要在应用export 对应io number。
fd = open("/sys/class/gpio/export", O_WRONLY);
len = snprintf(buffer, sizeof(buffer), "%d", pin);
if (write(fd, buffer, len) < 0) {
}
这里的export
和unport
以及之后对 io number value的read write
操作都是在gpiolibc
上实现的。
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_WRONLY);
if (fd < 0) {
}
if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0) {
}
接下来需要理一理gpiolibc
的实现,gpiolibc
所有操作都是基于gpio_desc *desc
变量。改变量通过gpio_desc
结构体定义这里的数组。数组索引就对应我们这里的io number。
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
这个结构体的实现主要是是通过gpio_chip
来操作的,例如gpiod_set_value
是通过gpio_desc
获取到gpio_chip
然后在通过gpio_chip->set()
实现IO的读写。
static void gpiod_set_value(struct gpio_desc *desc, int value) {
struct gpio_chip *chip;
if (!desc)
return;
chip = desc->chip;
/* Should be using gpio_set_value_cansleep() */
WARN_ON(chip->can_sleep);
trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
_gpio_set_open_source_value(desc, value);
else
chip->set(chip, gpio_chip_hwgpio(desc), value);
}
所以对于gpio_chip
的初始化就很重要了。然而我并没有找。
static inline u32 sunxi_data_reg(u16 pin) {
u8 bank = pin / PINS_PER_BANK;
u32 offset = bank * BANK_MEM_SIZE;
offset += DATA_REGS_OFFSET;
offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
return round_down(offset, 4);
}
#define PINS_PER_BANK 32 //其中 PINS_PER_BANK 为32
对于如上计算的bank
1-7
依次对应 PB-PH
。
8
对应PL
Page.396 3.21. Port Controller(CPUx-PORT)
pin % PINS_PER_BANK
对于Port 尾号,例如pin=32,对应 PB0
#define IO_NUMBER_CARD_READER0 228 //!< PH4 (IC-D0_L) 读卡器信号0
#define IO_NUMBER_CARD_READER1 229 //!< PH5 (IC-D1_L) 读卡器信号1
#define IO_NUMBER_DOOR_CTRL 33 //!< PB1 (Core_OPEN)门禁控制
#define IO_NUMBER_DOOR_CHECK 64 //!< PC0 (button)按键选择(非门控制)
#define IO_NUMBER_USER_KEY 32 //!< PB0 (Userkey)用户按键
#define IO_NUMBER_A64_SHUTDOWN 359 //!< PL7 (Core_SHUTDOWN) 用MCU 控制 A64 软件开关机
#define IO_NUMBER_BODY_RADAR 232 //!< PH8 (Body_Sensor)人体雷达
#define IO_NUMBER_A64_SENSE //!< PH4 (Core_SENSE) 未知功能
shell 脚本转换
num2name(){
local num=$1
local h=$[$num/32]
local l=$[$num%32]
local H=$(echo -e `printf '\\\x%02x' $[0x41+h]`)
echo P$H$l
}
name2num(){
local name=$1
name=${name#P}
local H=${name:0:1}
local l=${name:1}
local h=$[`printf '%d' \'$H`-0x41]
echo $[h*32+l]
}