<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Linux 下操作gpio(兩種方法,驅動和mmap)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    目前我所知道的在linux下操作GPIO有兩種方法: 

    1.  編寫驅動,這當然要熟悉linux下驅動的編寫方法和技巧,在驅動里可以使用ioremap函數獲得GPIO物理基地址指針,然后使用這個指針根據ioctl命令進行GPIO寄存器的讀寫,并把結果回送到應用層。這里提供一點程序片斷供大家參考:

    [cpp] view plain copy  
    1.   int  init_module(void){   
    2.   
    3.         printk(KERN_ALERT "ioctl load.\r\n");   
    4.   
    5.     register_chrdev(254,"ioreg",&fops);   
    6.   
    7.         stb_gpio = (STBX25XX_GPIO_REG *)ioremap(GPIO_BASE,GPIO_LEN);   
    8.   
    9.     if(stb_gpio == NULL){   
    10.   
    11.             printk(KERN_ALERT "can''t get io base.\r\n");   
    12.   
    13.         return -1;   
    14.   
    15.         }   
    16.   
    17.     return 0;   
    18.   
    19. }   
    20.   
    21. int io_ioctl (struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg){  
    22.   
    23.     unsigned long uGpio;   
    24.   
    25.     printk(KERN_ALERT "io_ioctl cmd=%04x,arg=%04x.\r\n",cmd,(int)arg);   
    26.   
    27.     switch(cmd){   
    28.   
    29.         case SET_IO_DIR:{   
    30.   
    31.              printk(KERN_ALERT "SET_IO_DIR\r\n");   
    32.   
    33.              break;   
    34.   
    35.         }   
    36.   
    37.         case SET_IO_VALUE:{   
    38.   
    39.              printk(KERN_ALERT "SET_IO_VALUE\r\n");   
    40.   
    41.              break;   
    42.   
    43.         }   
    44.   
    45.         case GET_IO_VALUE:{   
    46.   
    47.              printk(KERN_ALERT "GET_IO_VALUE\r\n");   
    48.   
    49.              uGpio = stb_gpio->GPI;   
    50.   
    51.              printk(KERN_ALERT "GPIO = %08x",(int)uGpio);   
    52.   
    53.              copy_to_user((void *)arg,(const void *) &uGpio,sizeof(uGpio));   
    54.   
    55.              break;   
    56.   
    57.         }   
    58.   
    59.         case GET_IO_DIR:{   
    60.   
    61.              printk(KERN_ALERT "GET_IO_DIR\r\n");   
    62.   
    63.              break;   
    64.   
    65.         }   
    66.   
    67.     }   
    68.   
    69.     return 0;   
    70.   
    71. }   
    72.   
    73.     



      

    2.  在應用層使用mmap函數在應用層獲得GPIO物理基地址對應的虛擬地址指針,然后使用這個指針來讀寫GPIO寄存器,這里提供一點程序片斷供大家參考: 

     

    [cpp] view plain copy  
    1. char dev_name[] = "/dev/mem";   
    2.   
    3.         GPIO_REGISTER  *gpio_base;   
    4.   
    5.         fd  =  open(dev_name,O_RDWR);   
    6.   
    7.         if(fd<0){   
    8.   
    9.                printf("open %s is error\n",dev_name);   
    10.   
    11.                return -1 ;   
    12.   
    13.         }   
    14.   
    15.         gpio_base = (GPIO_REGISTER *)mmap( 0, 0x32, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0x40060000 );  
    16.   
    17.         if(gpio_base == NULL){   
    18.   
    19.                 printf("gpio base mmap is error\n");   
    20.   
    21.                 close(fd);   
    22.   
    23.                 return -1;   
    24.   
    25.         }   
    26.   
    27.         gpio_base->or  = (gpio_base->or & 0x7fffffff);   




    mmap

    功能描述: 
    mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。
    基于文件的映射,在mmap和munmap執行過程的任何時刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒有得到更新,首次對映射區的第一個頁索引時會更新該字段的值。用PROT_WRITE 和 MAP_SHARED標志建立起來的文件映射,其st_ctime 和 st_mtime
    在對映射區寫入之后,但在msync()通過MS_SYNC 和 MS_ASYNC兩個標志調用之前會被更新。

    用法:  
    #include <sys/mman.h>
    void *mmap(void *start, size_t length, int prot, int flags,
        int fd, off_t offset);
    int munmap(void *start, size_t length); 

    參數:   
    start:映射區的開始地址。
    length:映射區的長度。
    prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起
    PROT_EXEC //頁內容可以被執行
    PROT_READ  //頁內容可以被讀取
    PROT_WRITE //頁可以被寫入
    PROT_NONE  //頁不可訪問
    flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體
    MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區重疊于現存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。并且起始地址必須落在頁的邊界上。
    MAP_SHARED //與其它所有映射這個對象的進程共享映射空間。對共享區的寫入,相當于輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。
    MAP_PRIVATE //建立一個寫入時拷貝的私有映射。內存區域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。
    MAP_DENYWRITE //這個標志被忽略。
    MAP_EXECUTABLE //同上
    MAP_NORESERVE //不要為這個映射保留交換空間。當交換空間被保留,對映射區修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區的修改會引起段違例信號。
    MAP_LOCKED //鎖定映射區的頁面,從而防止頁面被交換出內存。
    MAP_GROWSDOWN //用于堆棧,告訴內核VM系統,映射區可以向下擴展。
    MAP_ANONYMOUS //匿名映射,映射區不與任何文件關聯。
    MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。
    MAP_FILE //兼容標志,被忽略。
    MAP_32BIT //將映射區放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平臺上得到支持。
    MAP_POPULATE //為文件映射通過預讀的方式準備好頁表。隨后對映射區的訪問不會被頁違例阻塞。
    MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義。不執行預讀,只為已存在于內存中的頁面建立頁表入口。
    fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。
    offset:被映射對象內容的起點。
      
        
    返回說明:   
    成功執行時,mmap()返回被映射區的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值   
    EACCES:訪問出錯
    EAGAIN:文件已被鎖定,或者太多的內存已被鎖定
    EBADF:fd不是有效的文件描述詞
    EINVAL:一個或者多個參數無效
    ENFILE:已達到系統對打開文件的限制
    ENODEV:指定文件所在的文件系統不支持內存映射
    ENOMEM:內存不足,或者進程已超出最大內存映射數量
    EPERM:權能不足,操作不允許
    ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志
    SIGSEGV:試著向只讀區寫入
    SIGBUS:試著訪問不屬于進程的內存區

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全