Linux 用戶態設置GPIO控制


Linux 用戶態設置GPIO控制

linux內核提供了一套在用戶態配置GPIO的接口,在/sys/class/gpio/目錄下 
這里寫圖片描述
可以發現其中包含有兩個文件exportunexport和若干gpiochipN 類型文件夾

  • export 
    用於將指定編號的引腳導出,作為GPIO使用
  • unexport 
    用於將導出的GPIO刪除掉
  • gpiochipN 
    當前芯片中包含的GPIO控制器

GPIO使用方法

  • 添加設備接口GPIO167 
    輸入:echo 167 > export 
    這里寫圖片描述
    可以發現,目錄下出現了gpio167,如果執行命令后沒有反應,表示當前的GPIO已經用作其他的功能,例如作為IIC的引腳等
  • 刪除設備接口GPIO167 
    輸入:echo 167 > unexport 
    這里寫圖片描述
    可以發現當前導出的接口被刪除
  • 控制設備接口GPIO167 
    輸入:echo 167 > unexport 
    這里寫圖片描述

    • direction 
      設置輸出還是輸入模式 
      • 設置為輸入:echo “in” > direction
      • 設置為輸出:echo “out” > direction
    • value 
      輸出時,控制高低電平;輸入時,獲取高低電平 
      • 高電平:echo 1 > value
      • 低電平:echo 0 > value
    • edge 
      控制中斷觸發模式,引腳被配置為中斷后可以使用poll() 函數監聽引腳 
      • 非中斷引腳: echo “none” > edge
      • 上升沿觸發:echo “rising” > edge
      • 下降沿觸發:echo “falling” > edge
      • 邊沿觸發:echo “both” > edge

gpiochipN目錄

用來管理和控制一組gpio端口的控制器

    • base 
      和N相同,表示控制器管理的最小的端口編號。
    • lable 
      診斷使用的標志(並不總是唯一的)
    • ngpio
      控制器管理的gpio端口數量(端口范圍是:N ~ N+ngpio-1)

      參考:http://blog.csdn.net/mirkerson/article/details/8464290

    • 用戶態使用gpio監聽中斷

    • 比如我想監聽PA7上的電平變化(也就是邊沿觸發),那么應該先向“/sys/class/gpio/gpio7/direction”寫入“in”,然后向“/sys/class/gpio/gpio7/edge”寫入“both”,然后對”/sys/class/gpio/gpio7/value”執行select/poll操作。

      代碼如下:

      poll_test.c

      #include <stdio.h>
      #include <fcntl.h>
      #include <poll.h>
      #include <unistd.h>
      
      int main()
      {
          int fd=open("/sys/class/gpio/gpio7/value",O_RDONLY);
          if(fd<0)
          {
              perror("open '/sys/class/gpio/gpio7/value' failed!\n");  
              return -1;
          }
          struct pollfd fds[1];
          fds[0].fd=fd;
          fds[0].events=POLLPRI;
          while(1)
          {
              if(poll(fds,1,0)==-1)
              {
                  perror("poll failed!\n");
                  return -1;
              }
              if(fds[0].revents&POLLPRI)
              {
                  if(lseek(fd,0,SEEK_SET)==-1)
                  {
                      perror("lseek failed!\n");
                      return -1;
                  }
                  char buffer[16];
                  int len;
                  if((len=read(fd,buffer,sizeof(buffer)))==-1)
                  {
                      perror("read failed!\n");
                      return -1;
                  }
                  buffer[len]=0;
                  printf("%s",buffer);
              }
          }
          return 0;
      }
      

      這個小程序的作用就是就是不斷poll(“/sys/class/gpio/gpio7/value”)。一旦poll()返回,就輸出PA7的值。

      假設代碼放在~目錄下,然后輸入如下命令:

      cd ~
      gcc poll_test.c -o poll_test
      echo in > /sys/class/gpio/gpio7/direction
      echo both > /sys/class/gpio/gpio7/edge
      ./poll_test
      

      用1K電阻把PA7上拉到VCC,然后用一根導線把PA7與GND連接又斷開,會發現不斷輸出1和0(當PA7連上GND的瞬間輸出0,與GND斷開的瞬間輸出1)。說明poll()確實能檢測到電平變化。

    • Linux應用]通過sysfs在用戶空間使用GPIO中斷


      • 通過使用sysfs,Linux GPIO可以支持在用戶空間進行GPIO的控制或獲取狀態。這樣可以使用簡單的工具,比如“echo”來設置輸出GPIO的電平或使用“cat”來讀取輸入GPIO的當前值。
        1、配置內核中sysfs下的GPIO支持
               要想在用戶空間訪問GPIO,需要在sysfs中使能GPIO支持。
        Symbol: GPIO_SYSFS [=n]
          Type  : boolean
          Prompt: /sys/class/gpio/... (sysfs interface)
          Defined at drivers/gpio/Kconfig:51
          Depends on: GPIOLIB [=y] && SYSFS [=y] && EXPERIMENTAL [=y]
          Location:
           -> Device Drivers
             -> GPIO Support (GPIOLIB [=y])
        2、在用戶空間是能GPIO
               即將GPIO導出到用戶空間之中。
        ------------------------------------
        GPIO = 22
        cd = /sys/class/gpio
        ls
        echo $GPIO > export
        ls
        ------------------------------------
               注意:開始ls時,gpio22並不存在,第二個ls時,gpio22才存在。
               設置為輸入並獲取當前值:
        ------------------------------------
        cd /sys/class/gpio/gpio$GPIO
        echo "in" > direction
        cat value
        ------------------------------------
               設置為輸出並設置值:
        ------------------------------------
        cd /sys/class/gpio/gpio$GPIO
        echo "out" > direction
        echo 1 > value 或 echo 0 > value
        ------------------------------------
        3、用作中斷
               先將GPIO配置為輸入,然后使用poll()來阻塞程序直到GPIO的輸入電平發生改變,關鍵是使用POLLPRI而不是POLLIN來偵聽事件;或者使用select()。
        4、查看GPIO配置
               配置內核來使能debugfs
         Symbol: DEBUG_FS [=y]
          Type  : boolean
          Prompt: Debug Filesystem
            Defined at lib/Kconfig.debug:77
            Location:
            -> Kernel hacking
               啟動目標硬件並掛載debugfs
        mount -t debugfs none /sys/kernel/debug
               查看引腳配置
        cat /sys/kernel/debug/gpio
         
        poll示例:
        memset((void *)xfds, 0, sizeof(xfds));
        xfds[0].fd = fd;
        xfds[0].events = POLLPRI;
        ret = poll(xfds, 1, -1);
        if(ret <= 0)
        ERREXIT("poll value");
        if(xfds[0].revents & POLLPRI)
        {
        /* get value */
        ret = lseek(fd, 0, SEEK_SET);
        if(ret < 0)
        ERREXIT("lseek value");
        ret = read(fd, buf, 2);
        buf[1] = '\0';
        printf("read ret = %d, value = %s\n", ret, buf);
        if(ret != 2)
        ERREXIT("read value");
        }
         
        select示例:
        FD_ZERO(&exceptfds);
        FD_SET(fd, &exceptfds);
        ret = select(fd+1,NULL,NULL,&exceptfds,NULL);
        if(ret < 0)
        ERREXIT("select value");
        //else if(ret > 0)
        if(ret > 0)
        {
        /* get value */
        ret = lseek(fd, 0, SEEK_SET);
        if(ret < 0)
        ERREXIT("lseek value");
        ret = read(fd, buf, 2);
        buf[1] = '\0';
        printf("read ret = %d, value = %x\n", ret, buf[0]);
        if(ret != 2)
        ERREXIT("read value");
        }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM