Skip to content

driver - 避免写内核驱动

user-sapce driver vs kernel driver

[[toc]]

GPIO

sysfs

https://openwrt.org/docs/techref/hardware/port.gpio

linux内核中有sysfs, 可以通过操作 /sys/class/gpio目录下的文件来控制gpio口的高低电平、中断等等

export: 将gpio口写入该文件中,将gpio导出到user space中

gpiochip0 gpiochip32 gpiochip64: 芯片有这几组gpio口,每组gpio口有32个pin

unexport: 与export相反的操作

echo 37 > /sys/class/gpio/export
# 如果成功,会在生成一个目录
ls /sys/class/gpio/gpio37

interrupts

gpio可以产生中断,/sys/class/gpio/gpio37目录下的edge文件可以用来处理中断

可以写入的参数有 none rising falling both

echo falling > /sys/class/gpio/gpio37/edge
# 配置下降沿中断,对于中断,可以使用poll/epoll等监听中断事件

gpio-cdev

网关有如下的 ls /dev/gpiochi* 设备号,可以使用ioctl来访问

/*
* Demonstrate using gpio cdev to output a single bit
* On a BeagleBone Black, GPIO1_21 is user LED 1
*/
#include <unistd.h> 
#include <stdlib.h>
#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/ioctl.h> 
#include <linux/gpio.h>

int main(void)
{
    int f; int ret;
    struct gpiohandle_request req; 
    struct gpiohandle_data data;
    f = open("/dev/gpiochip1", O_RDONLY);
    req.lineoffsets[0] = 21;
    req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */ 
    req.default_values[0] = 0;
    strcpy(req.consumer_label, "gpio-output"); /* up to 31 characters */ 
    req.lines = 1;
    ret = ioctl(f, GPIO_GET_LINEHANDLE_IOCTL, &req);
    /* Note that there is a new file descriptor in req.fd to handle the GPIO lines */
    data.values[0] = 1;
    ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); close(f);
    return 0;
}

PWM

PWM通常用来控制灯光的亮度,或者电机的转速

sysfs

跟上面gpio的情况类似

# ls /sys/class/pwm/pwmchip0
  device 
  export -> Write to this file to export a PWM to user space
  npwm
  power 
  subsystem 
  uevent 
  unexport ->   Write to this file to unexport a PWM to user space
# echo 0 > /sys/class/pwm/pwmchip0/export 
# ls /sys/class/pwm/pwmchip0
device export npwm power pwm0 subsystem uevent unexport
# 上面命令如果成功,会有如下目录
# ls /sys/class/pwm/pwmchip0/pwm0
capture  duty_cycle  export  period power   uevent device   enable  npwm    polarity subsystem unexport

image-20221206222156262

# 设置period为1ms(1000 000ns), duty为0.5ms(500 000ns)
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period 
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

I2C

I2C通常用于连接传感器,比如温度传感器

Each I2C device has a 7-bit address, usually hard wired

16 bus addresses are reserved, giving a maximum of 112 nodes per bus

The master controller manages read/write transfers with slave nodes

i2c-dev exposes I2C master controllers

Need to load/configure the i2c-dev driver (CONFIG_I2C_CHARDEV)

There is one device node per i2c master controller

# ls -l /dev/i2c*
crw-rw---T 1 root i2c 89, 0 Jan 1   2000 /dev/i2c-0
crw-rw---T 1 root i2c 89, 1 Jan 1   2000 /dev/i2c-1

You access I2C slave nodes using read(2), write(2) and ioctl(2)

Structures defined in usr/include/linux/i2c-dev.h

i2cdetect, from i2c-tools package, lists i2c adapters and probes devices

Example: detect devices on bus 1 (/dev/i2c-1)

# i2cdetect -y -r 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
# UU = device already handled by kernel driver 
# 0x39 = device discovered at address 0x39

i2cget \<bus> \<chip> \<register>: read data from an I2C device

Example: read register 0x8a from device at 0x39

# i2cget -y 1 0x39 0x8a 0x50

i2cset \<bus> \<chip> \<register>: writedata to an I2C device

Example: Write 0x03 to register 0x80:

# i2cset -y 1 0x39 0x80 3
#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <sys/ioctl.h> 
#include <linux/i2c-dev.h>

int main(int argc, char **argv) 
{
    int f;
    char buf[4];

    f = open("/dev/i2c-1", O_RDWR); ioctl(f, I2C_SLAVE, 0x39) < 0) {
        buf[0] = 0x8a;  /* Chip ID register */
        write(f, buf, 1);
        read(f, buf, 1);
        printf("ID 0x%x\n", buf[0]);
    }
}