君正X系列开发---GPIO在用户空间使用&platform_device驱动&gpiolib库的使用5

时间:2022-08-22 17:49:59
可以通过导出gpio sys节点到用户空间,在用户空间操作。
内核的gpio驱动基于gpio子系统的实现,所以其他驱动程序可以通过内核提供的
libgpio
接口很方面的控制,例如,gpio_request_one,gpio_get_value,gpio_set_value

如果用gpio的方式控制led,需要改哪些呢?

驱动中选中gpioled,板级里找到LED_GPIO的宏,改成您自己用的gpio


X1000 的gpio 控制器有五组,A,B,C,D,Z。
支持输入输出和设备复用功能。内核的gpio 驱动程序是基于gpio 子系统架构编写的。应用
程序可以使用gpio_demo 进行测试。内核驱动可以在内核空间使用,也可以通过导出gpio sys 节
点到用户空间,在用户空间进行操作

内核空间
文件介绍
gpio 一般在进行开发板设计的时候就已经固定好了,有的gpio 只能作为设备复用功能管脚,
有的gpio 作为普通的输入输出和中断检测功能,对于固定设备复用的功能管脚在以下文件中定
义:
arch/mips/xburst/soc-x1000/include/mach/platform.h
在arch/mips/xburst/soc-x1000/common/platform.c 会根据驱动配置,选中相应的设备功能管脚。
内核的gpio 驱动基于gpio 子系统实现,所以其它驱动程序可以通过内核提供的libgpio 接口,
很方便的进行gpio 控制,例如gpio_request_one, gpio_get_value,gpio_set_value 等。
gpio 驱动文件所在位置:
arch/mips/xburst/soc-x1000/common/gpio.c
编译配置
内核通过配置CONFIG_GPIOLIB 选项可以使用gpio 功能,默认必须选上。
CONFIG_GPIOLIB:
Symbol: GPIOLIB [=y]
Type : boolean
Prompt: GPIO Support
Location:
-> Device Drivers
Defined at drivers/gpio/Kconfig:38
Depends on: ARCH_WANT_OPTIONAL_GPIOLIB [=n] || ARCH_REQUIRE_GPIOLIB [=y]

通过配置CONFIG_GPIO_SYSFS 选项,可以将gpio 导出到用户节点/sys/class/gpio 下,对该
节点下的文件操作,可以控制gpio 输入输出。
Symbol: GPIO_SYSFS [=y]
Type : boolean
Prompt: /sys/class/gpio/... (sysfs interface)
Location:
-> Device Drivers
-> GPIO Support (GPIOLIB [=y])
Defined at drivers/gpio/Kconfig:69

Depends on: GPIOLIB [=y] && SYSFS [=y]

用户空间
在内核导出gpio 节点的前提下,可以操作/sys/class/gpio 节点,控制gpio 输入输出。
/sys/class/gpio/
"export" ... 用户空间可以通过写其编号到这个文件,要求内核导出
一个GPIO 的控制到用户空间。
例如: 如果内核代码没有申请GPIO #19,"echo 19 > export"
将会为GPIO #19 创建一个"gpio19" 节点。

"unexport" ... 导出到用户空间的逆操作。
例如: "echo 19 > unexport" 将会移除使用"export"文件导出的
"gpio19" 节点。
GPIO 信号的路径类似/sys/class/gpio/gpio42/ (对于GPIO #42 来说),
并有如下的读/写属性:
/sys/class/gpio/gpioN/

"direction" ... 读取得到"in" 或"out"。这个值通常运行写入。
写入"out" 时,其引脚的默认输出为低电平。为了确保无故障运行,
"low" 或"high" 的电平值应该写入GPIO 的配置,作为初始输出值。
注意:如果内核不支持改变GPIO 的方向,或者在导出时内核代码没
有明确允许用户空间可以重新配置GPIO 方向,那么这个属性将不存
在。

"value" ... 读取得到0 (低电平) 或1 (高电平)。如果GPIO 配置为
输出,这个值允许写操作。任何非零值都以高电平看待。
如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式
(见"edge"的描述),你可以对这个文件使用轮询操作(poll(2)),
且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)),
请在events 中设置POLLPRI 和POLLERR。如果你使用轮询操作
(select(2)),请在exceptfds 设置你期望的文件描述符。在
轮询操作(poll(2))返回之后,既可以通过lseek(2)操作读取
sysfs 文件的开始部分,也可以关闭这个文件并重新打开它来读取数
据。


"edge" ... 读取得到“none”、“rising”、“falling”或者“both”。
将这些字符串写入这个文件可以选择沿触发模式,会使得轮询操作
(select(2))在"value"文件中返回。
这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存
在。
"active_low" ... 读取得到0 (假) 或1 (真)。写入任何非零值可以
翻转这个属性的(读写)值。已存在或之后通过"edge"属性设置了
"rising"



gpio操作                   查看Documentation/gpio.txt文档

 

4.3. GPIO 模块

X1000的gpio 控制器有五组,A,B,C,D,Z。

支持输入输出和设备复用功能。内核的gpio 驱动程序是基于gpio 子系统架构编写的。应用程序可以使用gpio_demo 进行测试。内核驱动可以在内核空间使用,也可以通过导出gpiosys 节点到用户空间,在用户空间进行操作。

内核空间

对于固定设备复用的功能管脚在以下文件中定

义:

arch/mips/xburst/soc-x1000/include/mach/platform.h

在arch/mips/xburst/soc-x1000/common/platform.c 会根据驱动配置,选中相应的设备功能管脚。

Platform.h中

/*

 * Copyright (C) 2010 Ingenic Semiconductor Inc.

 *

 *   Inthis file, here are some macro/device/function to

 * to help the board special file to organizeresources

 * on the chip.

 */

 

#ifndef __SOC_x1000_H__

#define __SOC_x1000_H__

 

/* devio define list */

/****************************************************************************************/

#define I2S_PORTB                          \

    {.name = "i2s", .port = GPIO_PORT_B, .func =GPIO_FUNC_1, .pins = 0x1f, }

/****************************************************************************************/

#define UART0_PORTC                            \

    {.name = "uart0", .port = GPIO_PORT_C, .func =GPIO_FUNC_0, .pins = 0x0f << 10, }

#define UART1_PORTA                            \

    {.name = "uart1-pa", .port = GPIO_PORT_A, .func =GPIO_FUNC_2, .pins = 0x3 << 4, }

#ifndef CONFIG_PRODUCT_X1000_BEETHOVEN

#define UART1_PORTD                            \

    {.name = "uart1-pd", .port = GPIO_PORT_D, .func =GPIO_FUNC_1, .pins = 0xf << 2, }

#else

#define UART1_PORTD                            \

    { .name = "uart1-pd", .port =GPIO_PORT_D, .func = GPIO_FUNC_1, .pins = 0x3 << 2, }

#endif

#define UART2_PORTA                            \

    {.name = "uart2-pa", .port = GPIO_PORT_A, .func =GPIO_FUNC_2, .pins = 0x3 << 2, }

#define UART2_PORTD                            \

    {.name = "uart2-pd", .port = GPIO_PORT_D, .func =GPIO_FUNC_0, .pins = 0x3 << 4 }

#define UART2_PORTC                            \

    {.name = "uart2-pc", .port = GPIO_PORT_C, .func =GPIO_FUNC_1, .pins = 0x1 << 31 }

/****************************************************************************************/

 

/* JZ SoC on Chip devices list*/

extern struct platform_device jz_codec_device;

 

extern struct platform_device jz_fb_device;

 

extern struct platform_device jz_uart0_device;

extern struct platform_device jz_uart1_device;

extern struct platform_device jz_uart2_device;

 

int jz_device_register(structplatform_device *pdev,void *pdata);

 

#endif

 

http://blog.csdn.net/ghostyu/article/details/6908805

在kernel/include/linux/platform.h中定义结构体

struct platform_device {

    const char *name;

    int     id;

    bool        id_auto;

    struct device  dev;

    u32     num_resources;

    struct resource    *resource;

 

    const struct platform_device_id   *id_entry;

 

    /* MFD cell pointer */

    struct mfd_cell *mfd_cell;

 

    /* arch specific additions */

    struct pdev_archdata   archdata;

};

函数extern intplatform_device_register(struct platform_device *);在文件kernel/drivers/base/platform.c中

/**

 * platform_device_register - add aplatform-level device

 * @pdev: platform device we're adding

 */

int platform_device_register(structplatform_device *pdev)

{

    device_initialize(&pdev->dev);

    arch_setup_pdev_archdata(pdev);

    return platform_device_add(pdev);

}

EXPORT_SYMBOL_GPL(platform_device_register);

 

文件arch/mips/xburst/soc-x1000/common/platform.c根据配置选项选中相应的设备功能引脚

#ifdef CONFIG_SERIAL_JZ47XX_UART2          //如果定义该选项

//在该板级配置文档中kernel/arch/mips/configs/halley2_nor_v10_linux_defconfig

static struct resource jz_uart2_resources[] = {

    [0] = {

        .start          = UART2_IOBASE,//基地址arch/mips/xburst/soc-x1000/include/soc

  //#defineUART0_IOBASE    0x10030000

        .end            = UART2_IOBASE + 0x1000 - 1,

        .flags          = IORESOURCE_MEM,

    },

    [1] = {

        .start          = IRQ_UART2,

        .end            = IRQ_UART2,

        .flags          = IORESOURCE_IRQ,

    },

#ifdef CONFIG_SERIAL_JZ47XX_UART2_DMA

    [2] = {

        .start          = JZDMA_REQ_UART2,

        .flags          = IORESOURCE_DMA,

    },

#endif

};

 

struct platform_device jz_uart2_device = {

    .name = "jz-uart",

    .id = 2,

    .num_resources  =ARRAY_SIZE(jz_uart2_resources),

    .resource       = jz_uart2_resources,

};

#endif

platform_deviceplatform_driver(一)

首先介绍一下注册一个驱动的步骤:

1、定义一个platform_driver结构

2、初始化这个结构,指定其probe、remove等函数,并初始化其中的driver变量

3、实现其probe、remove等函数

看platform_driver结构,定义于include/Linux/platform_device.h文件中:

struct platform_driver {

    int (*probe)(structplatform_device *);

    int (*remove)(structplatform_device *);

    void (*shutdown)(structplatform_device *);

    int (*suspend)(structplatform_device *, pm_message_t state);

    int (*resume)(structplatform_device *);

    struct device_driver driver;

    const struct platform_device_id *id_table;

};

包含device_driver 结构体,该结构体在include/linux/device.h中

/**

 * struct device_driver - The basicdevice driver structure

 * @name:   Nameof the device driver.

 * @bus:    Thebus which the device of this driver belongs to.

 * @owner:  Themodule owner.

 * @mod_name:   Usedfor built-in modules.

 * @suppress_bind_attrs: Disables bind/unbindviasysfs.

 * @of_match_table: The open firmware table.

 * @acpi_match_table: The ACPI match table.

 * @probe:  Calledto query the existence of a specific device,

 *      whether this driver can work with it, andbind the driver

 *      to a specific device.

 * @remove: Calledwhen the device is removed from the system to

 *      unbind a device from this driver.

 * @shutdown:   Calledat shut-down time toquiesce the device.

 * @suspend:    Calledto put the device to sleep mode. Usually to a

 *      low power state.

 * @resume: Calledto bring a device from sleep mode.

 * @groups: Defaultattributes that get created by the driver core

 *      automatically.

 * @pm:     Power management operations of the devicewhich matched

 *      this driver.

 * @p:      Driver core's private data, no one otherthan the driver

 *      core can touch this.

 *

 * The device driver-model tracks all of thedrivers known to the system.

 * The main reason for this tracking is toenable the driver core to match

 * up drivers with new devices. Once driversare known objects within the

 * system, however, a number of other thingsbecome possible. Device drivers

 * can export information and configurationvariables that are independent

 * of any specific device.

 */

struct device_driver {

    const char     *name;

    struct bus_type        *bus;

 

    struct module      *owner;

    const char     *mod_name/* used for built-in modules */

 

    bool suppress_bind_attrs;   /* disables bind/unbindviasysfs */

 

    const struct of_device_id *of_match_table;

    const struct acpi_device_id   *acpi_match_table;

 

    int (*probe) (structdevice *dev);

    int (*remove) (structdevice *dev);

    void (*shutdown) (structdevice *dev);

    int (*suspend) (structdevice *dev, pm_message_t state);

    int (*resume) (structdevice *dev);

    const struct attribute_group **groups;

 

    const struct dev_pm_ops *pm;

 

    struct driver_private *p;

};

刚才提到了注册一个驱动需要初始化该结构体

需要注意两个变量name和owner。name的作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。

 

下面是一个platform初始化实例:

Serial为例

kernel/drivers/tty/serial/jz_uart.c:       .name  = "jz-uart", 

 

static struct platform_driverserial_jz47xx_driver = {

    .probe          =serial_jz47xx_probe,

    .remove         =serial_jz47xx_remove,

 

    .driver     = {

        .name   ="jz-uart",

        .owner  =THIS_MODULE,

#ifdef CONFIG_PM

        .pm = &serial_jz47xx_pm_ops,

#endif

    },

};

 

int __init serial_jz47xx_init(void)

{

    int ret;

 

    ret =uart_register_driver(&serial_jz47xx_reg);

    if (ret != 0)

        return ret;

 

    ret =platform_driver_register(&serial_jz47xx_driver);

    if (ret != 0)

        uart_unregister_driver(&serial_jz47xx_reg);

 

    return ret;

}

 

void __exit serial_jz47xx_exit(void)

{

    platform_driver_unregister(&serial_jz47xx_driver);

    uart_unregister_driver(&serial_jz47xx_reg);

}

 

 

#ifdef CONFIG_EARLY_INIT_RUN

rootfs_initcall(serial_jz47xx_init);

 

#else

module_init(serial_jz47xx_init);

 

#endif

 

module_exit(serial_jz47xx_exit);

 

MODULE_LICENSE("GPL");

MODULE_ALIAS("platform:jz47xx-uart");

上述是串口驱动,serial_jz47xx_driver结构体初始化了name、owner,

看下另一个结构、 structplatform_device该结构体也有name变量,

platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。platform_device就描述了设备对象。下面是一个具体的实例:

 

//arch/mips/xburst/soc-x1000/common/platform.c文件中

struct platform_device jz_uart2_device = {

    .name = "jz-uart",

    .id = 2,        //ttyS2

    .num_resources  =ARRAY_SIZE(jz_uart2_resources),

    .resource       =jz_uart2_resources,

};

 它的name变量和刚才上面的platform_driver的name变量是一致的,内核正是通过这个一致性来为驱动程序找到资源,即platform_device中的resource。这个结构的定义如下,位于include/linux/ioport.h中:

struct resource {
    resource_size_t start;
    resource_size_t end;
    const char *name;
    unsigned long flags;
    struct resource *parent, *sibling, *child;
};

 

//arch/mips/xburst/soc-x1000/common/platform.c文件中

#ifdef CONFIG_SERIAL_JZ47XX_UART2

static struct resource jz_uart2_resources[] = {

    [0] = {

        .start          = UART2_IOBASE,

        .end            = UART2_IOBASE + 0x1000 - 1,

        .flags          = IORESOURCE_MEM,

    },

    [1] = {

        .start          = IRQ_UART2,

        .end            = IRQ_UART2,

        .flags          = IORESOURCE_IRQ,

    },

#ifdef CONFIG_SERIAL_JZ47XX_UART2_DMA

    [2] = {

        .start          = JZDMA_REQ_UART2,

        .flags          = IORESOURCE_DMA,

    },

#endif

};

 这个结构的作用就是告诉驱动程序设备的起始地址和终止地址和设备的端口类型。这里的地址指的是物理地址。

另外还需要注意platform_device中的device结构,它详细描述了设备的情况

 

驱动的实现

做Linux方面也有三个多月了,对代码中的有些结构一直不是很明白,比如platform_device与platform_driver一直分不清关系。在网上搜了下,做个总结。两者的工作顺序是先定义platform_device -> 注册platform_device->,再定义 platform_driver-> 注册 platform_driver。

     platform_device设备的注册过程必须在相应设备驱动加载之前被调用,因为驱动注册时需要匹配内核中所以已注册的设备名。platform_device 是在系统启动时在init.c 里的s3c_arch_init()函数里进行注册的。这个函数申明为arch_initcall(s3c_arch_init);会在系统初始化阶段被调用。arch_initcall 的优先级高于module_init,所以会在Platform驱动注册之前调用。现在内核中不是采用arch_initcall(s3c_arch_init) 注册platform_device结构体而是通过.init_machine成员将其保存在arch_initcall(customize_machine)等待调用(在mach-smdk6410.c中定义的MACHINE_START到MACHINE_END);其实质是一样的均放在.initcall3.init等待调用。之后再定义结构体struct platform_driver,在驱动初始化函数中调用函数platform_driver_register()注册 platform_driver。详细过程描述如下:

     Linux从2.6版本开始引入了platform这个概念,在开发底层驱动程序时,首先要确认的就是设备的资源信息,在2.6内核中将每个设备的资源用结构platform_device来描述,该结构体定义在kernel/include/linux/platform_device.h中,

struct platform_device

{
      const char * name;
      u32  id;
      struct device dev;
      u32  num_resources;
      struct resource * resource;
};

该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,
struct resource

{
       const char *name;
       unsigned long start, end;
       unsigned long flags;
       struct resource *parent, *sibling, *child;
};

比如:

static struct resource s3c_usb_resource[] = {
 [0] = {
       .start = S3C_PA_USBHOST,
       .end   = S3C_PA_USBHOST +S3C_SZ_USBHOST - 1,
       .flags = IORESOURCE_MEM,
     },
 [1] = {
       .start = IRQ_UHOST,
       .end   = IRQ_UHOST,
       .flags = IORESOURCE_IRQ,
     }
};

以上是6410的USB  HOST分配的资源信息。第1组描述了这个usbhost设备所占用的总线地址范围,起始地址和大小由硬件决定,IORESOURCE_MEM表示第1组描述的是内存类型的资源信息;第2组描述了这个usbhost设备的中断号,也由硬件设定,IORESOURCE_IRQ表示第2组描述的是中断资源信息。设备驱动会根据flags来获取相应的资源信息。

      有了resource信息,就可以定义platform_device了:

struct platform_device s3c_device_usb = {
         .name    ="s3c2410-ohci",  //s3c6410-usb
         .id    = -1,
         .num_resources   =ARRAY_SIZE(s3c_usb_resource),
         .resource   =s3c_usb_resource,
        .dev             = {
                .dma_mask = &s3c_device_usb_dmamask,
                .coherent_dma_mask = 0xffffffffUL
             }
};

有了platform_device就可以调用函数platform_add_devices向系统中添加该设备了。系统中的设备资源都可以采用这种方式列举在一起,然后成一个指针数组,如:

static struct platform_device *smdk6410_devices[]__initdata = {

......

 &s3c_device_usbgadget,
 &s3c_device_usb,  //jeff add.

......

}

然后在6410的初始化函数smdk6410_machine_init()中执行:

platform_add_devices(smdk6410_devices,ARRAY_SIZE(smdk6410_devices));将所有的device添加进系统。platform_add_devices的好处在于它是一次性的执行多个platform_device_register。

     至于驱动程序需要实现结构体struct platform_driver,也定义在kernel/include/linux/platform_device.h中:

struct platform_driver {
      int (*probe)(struct platform_device *);
      int (*remove)(struct platform_device *);
      void (*shutdown)(struct platform_device *);
      int (*suspend)(struct platform_device *,pm_message_t state);
      int (*suspend_late)(struct platform_device *,pm_message_t state);
      int (*resume_early)(struct platform_device *);
      int (*resume)(struct platform_device *);
      struct pm_ext_ops *pm;
      struct device_driver driver;
};

则该处的USB HOST实现是:

static struct platform_driverohci_hcd_s3c2410_driver = {
     .probe  = ohci_hcd_s3c2410_drv_probe,
     .remove  = ohci_hcd_s3c2410_drv_remove,
     .shutdown = usb_hcd_platform_shutdown,
     /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
     /*.resume = ohci_hcd_s3c2410_drv_resume, */
     .driver  = {
          .owner =THIS_MODULE,
          .name ="s3c2410-ohci",
        },
};

      在驱动初始化(ohci-hcd.c的1124行)函数中调用函数platform_driver_register()注册该platform_driver,需要注意的是s3c_device_usb结构中name元素和ohci_hcd_s3c2410_driver 结构中driver.name必须是相同的,这样在platform_driver_register()注册时会对所有已注册的platform_device中元素的name和当前注册的platform_driver的driver.name进行比较,只有找到具备相同名称的platform_device存在后,platform_driver才能注册成功。当注册成功时会调用platform_driver结构元素probe函数指针,这里就是ohci_hcd_s3c2410_drv_probe开始探测加载。platform driver中的函数都是以platformdevice作为参数进入。

     为什么两个name的名字必须匹配才能实现device和driver的绑定?(1)在内核初始化时kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()初始化platform_bus(虚拟总线);(2)设备注册的时候platform_device_register()->platform_device_add()->(pdev->dev.bus=&platform_bus_type)把设备挂在虚拟的platformbus下;(3)驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev(),对每个挂在虚拟的platformbus的设备作__driver_attach()->driver_probe_device(),判断drv->bus->match()是否存在并且是否执行成功,此时通过指针执行platform_match,比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就调用really_probe(实际就是执行的相应设备的platform_driver->probe(platform_device),注意platform_drv_probe的_dev参数是由bus_for_each_dev的next_device获得)开始真正的探测加载,如果probe成功则绑定该设备到该驱动。

      当进入probe函数后,需要获取设备的资源信息,根据参数type所指定类型,例如IORESOURCE_MEM,来分别获取指定的资源。
structresource * platform_get_resource(struct platform_device *dev, unsignedinttype, unsigned int num);当然,也可以固定资源类型,如获取资源中的中断号:struct intplatform_get_irq(struct platform_device *dev,unsigned int num);

      probe函数一般完成硬件设备使能,structresource的获取以及虚拟地址的动态映射和具体类型设备的注册(因为平台设备只是一种虚拟的设备类型);remove函数完成硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和具体类型设备的注销。只要和内核本身运行依赖性不大的外围设备 (换句话说只要不在内核运行所需的一个最小系统之内的设备 ), 相对独立的拥有各自独自的资源 (addresses and IRQs),都可以用platform_driver 实现。如:lcd,usb,uart 等,都可以用platfrom_driver写,而timer,irq等最小系统之内的设备则最好不用platfrom_driver 机制,实际上内核实现也是这样的。

 

 

 

 

Platform涉及的结构体及文件

structplatform_device                     //总线设备,板级文档中设置,随系统启动

struct platform_driver                      //总线驱动,module_init(serial_jz47xx_init);

 

arch/mips/xburst/soc-x1000/include/mach/platform.h   //板级设备宏定义

arch/mips/xburst/soc-x1000/common/platform.c //板级定义platform_device和resource

kernel/include/linux/platform.h     //struct platform_device定义

include/linux/ioport.h       //resource结构定义

 

kernel/drivers/tty/serial/jz_uart.c   //platform_driver驱动实现

kernel/drivers/tty/serial/jz_uart.h      //platform_driver驱动头文件

include/linux/platform_device.h //struct platform_driver定义

include/linux/device.h   //struct device_driver定义

 

gpio管脚定义在芯片的板级文档里:

/kernel/arch/mips/xburst/soc-x1000/chip-x1000/halley2/halley2_v10/board.h             //所有使用                                                               //的GPIO定义

内核空间代码

kernel/drivers/gpio/gpiolib.c

 

内核空间操作函数:

 intgpio_is_valid(int number);        //测试管脚的可用性

 

         /*set as input or output, returning 0 or negative errno */

         intgpio_direction_input(unsigned gpio);

         intgpio_direction_output(unsigned gpio, int value);     

         Thereturn value is zero for success

        

        

        

*******************************************

用户空间可使用库development/libs/gpio/

Build.mk gpio_device.cpp gpio_device.h  ModuleDescription

 

example:/packages/example/Demo/gpio_demo

#include <iostream>

#include <gpio_device.h>

 

int main(){

         GPIO_devicephoenix(12);

         phoenix.export_gpio();

 

         std::cout<< "Set pin 12 with in\n";

         phoenix.write_gpio("direction","in");

         std::cout<< "Set pin 12 with low\n";

         phoenix.write_gpio("direction","low");

 

         std::cout<< "Set pin 12 edge to both\n";

         phoenix.write_gpio("edge","both");

 

         if(phoenix.poll_gpio()){

                  std::cout << "Pin 12pushd\n";

         }

         return0;

}