美文网首页
Linux下使用mmap(/dev/mem)操作GPIO

Linux下使用mmap(/dev/mem)操作GPIO

作者: txfly | 来源:发表于2020-08-26 10:24 被阅读0次

    前面介绍了使用sysfs操作GPIO,这儿介绍另一种方式:mmap。mmap可以将物理设备/dev/mem映射到内存,通过读写内存的方式操作GPIO寄存器,使用起来速度比sysfs更快。

    测试环境: 飞凌OKMX8MM-C开发板

    使用寄存器操作GPIO时,需要设置的寄存器有:

    • Pad Mux Register,PAD复用寄存器
    • Pad Control Register,PAD控制寄存器
    • GDIR,GPIO 方向寄存器
    • DR,数据寄存器

    下面以GPIO5_IO00为例,先从手册中找到各寄存器的地址,并介绍基本配置。

    Pad Mux Register

    Pad Mux Register是端口复用寄存器,GPIO5_IO00复用的端口为SAI3_TXC,对应的寄存器为IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC,可以看到地址为0x303301DC,占用四个字节。文档内容如下图所示:

    Pad Mux Register
    Mux Mode 其中后三位用于设置复用模式。从表格中可以看到,MUX_MODE设置为101,可以复用为IO模式。

    Pad Control Register

    对应的寄存器为IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC,查手册可以看到地址为0x30330444

    Pad Control Register 本次实验中主要用到FSEL部分,设置为FAST模式,即0x10

    GDIR和DR

    GDIR和DR设置比较简单,所以放在一起说。根据手册可以看到,GPIO5对应的GDIR寄存器地址为0x30240004,DR寄存器地址为 0x30240000

    GDIR和DR 其中GDIR用于设置IO方向,具体内容为:
    GDIR介绍 从上面可以看到,如果我们使用GPIO某个引脚,将对应的位置1或者置0即可。这儿我们使用GPIO5_IO00用于输出,所以将GPIO5对应的GDIR寄存器0位置为1即可。

    同样,DR寄存器用于设置IO输出电平,将对应的位置1或置0即可:

    DR寄存器 我们使用的是GPIO5_IO00,所以操作GPIO5对应的DR寄存器第0位即可。

    综上所述,GPIO5_IO00对应的寄存器为:

    • Pad Mux Register,0x303301DC
    • Pad Control Register,0x30330444
    • GDIR,0x30240004
    • DR,0x30240000

    测试

    首先打开/dev/mem文件,然后使用mmap映射到内存。使用mmap时要注意起始位置、长度和偏移。在这里我从偏移为GPIO5_DR 0x30240000处开始映射,IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC 0x30330444处结束,共984132个字节。在这儿getpagesize()大小为4096,所以把长度设为getpagesize() * 250,这儿只要不小于实际长度就行。

    下面是完整测试代码:

    //
    // Created by txfly on 2020/8/26.
    //
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <string.h>
    #include <stdint.h>
    #include <unistd.h>
    
    // gpio5_00
    #define GPIO5_DR                         0x30240000
    #define GPIO5_GDIR                       0x30240004
    #define GPIO5_PSR                        0x30240008
    #define IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC   0x303301DC
    #define IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC   0x30330444
    
    static volatile uint32_t *gpio;
    
    int main(int argc, char **argv) {
        int fd;
        if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) {
            printf("Unable to open /dev/mem: %s\n", strerror(errno));
            return -1;
        }
    
        gpio = (uint32_t *) mmap(0, getpagesize() * 250, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO5_DR);
        if ((void *) gpio == MAP_FAILED) {
            printf("mmap failed: %s\n", strerror(errno));
            exit(1);
        }
    
        printf("start config mux...\n");
        *(gpio + (IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC - GPIO5_DR) / 4) |= 0x5;
        printf("start config pad...\n");
        *(gpio + (IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC - GPIO5_DR) / 4) |= 0x10;
        printf("start config direction...\n");
        *(gpio + (GPIO5_GDIR - GPIO5_DR) / 4) |= 0x1;
    
        printf("start...\n");
    
        while (1) {
            *gpio ^= 0x1;
            usleep(500000);
        }
    
        munmap(gpio, getpagesize() * 250);
        close(fd);
    }
    

    版权声明:本文为「txfly」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://www.jianshu.com/p/d4681baf0288

    相关文章

      网友评论

          本文标题:Linux下使用mmap(/dev/mem)操作GPIO

          本文链接:https://www.haomeiwen.com/subject/slvzjktx.html