嵌入式Linux 使用MMAP映射GPIO

嵌入式Linux 使用MMAP映射GPIO

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>



#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

#define GPIO_LED_BASE_ADDR      0x01c20800

#define PD_CFG_REG_1_OFFSET     ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0070)
#define PD_CFG_REG_2_OFFSET     ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0074)
#define PD_DATA_REG_OFFSET      ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x007C)
#define PD_DRV0_REG_OFFSET      ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0080)
#define PD_DRV1_REG_OFFSET      ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0084)
#define PD_PULL0_REG_OFFSET     ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0088)
#define PD_PULL1_REG_OFFSET     ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x008C)

#define GPIO_PD_09              9
#define GPIO_PD_18              18
#define GPIO_PD_19              19


int main(int argc, char * argv[])
{
    void * gpio;
    unsigned int reg;
    unsigned int * pd_cfg1_reg;
    unsigned int * pd_cfg2_reg;
    unsigned int * pd_data_reg;
    unsigned int * pd_drv0_reg;
    unsigned int * pd_drv1_reg;
    unsigned int * pd_pull0_reg;
    unsigned int * pd_pull1_reg;

    int mem_fd = -1;

    long sz = sysconf(_SC_PAGESIZE);    
    /*sz=4096,所以一页的大小为4096, MAP_SIZE必须为4096的整数倍, 否则mmap会返回22提示参数错误*/
    printf("#######_SC_PAGESIZE = %ld\n",sz);
 
    mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (mem_fd < 0) {
        printf("Unable to open /dev/mem\n");
        return -1;
    }
 
    gpio = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, GPIO_LED_BASE_ADDR & ~MAP_MASK);
    if (gpio  == MAP_FAILED) {
        printf("Mmap failed errno = %d\n", errno);
        close(mem_fd);
        return -1;
    }

    pd_cfg1_reg = gpio + PD_CFG_REG_1_OFFSET;
    pd_cfg2_reg = gpio + PD_CFG_REG_2_OFFSET;
    pd_data_reg = gpio + PD_DATA_REG_OFFSET;
    pd_drv0_reg = gpio + PD_DRV0_REG_OFFSET;
    pd_drv1_reg = gpio + PD_DRV1_REG_OFFSET;
    pd_pull0_reg = gpio + PD_PULL0_REG_OFFSET;
    pd_pull1_reg = gpio + PD_PULL1_REG_OFFSET;

    printf("CFG REG1:\n");
    printf("##################### %08x ####################\n", *pd_cfg1_reg);
    //PD9 set output mode
    *pd_cfg1_reg &= 0x00;
    *pd_cfg1_reg |= 0x10;
    printf("##################### %08x ####################\n", *pd_cfg1_reg);

    printf("CFG REG2:\n");
    printf("##################### %08x ####################\n", *pd_cfg2_reg);
    //PD18 and PD19 set output mode
    *pd_cfg2_reg &= 0x00;
    *pd_cfg2_reg |= 0x1100;
    printf("##################### %08x ####################\n", *pd_cfg2_reg);

    printf("DATA REG:\n");
    printf("##################### %08x ####################\n", *pd_data_reg);
    //set output high level
    *pd_data_reg  &= 0x00;
    *pd_data_reg  |= (0x01 << GPIO_PD_09);
    *pd_data_reg  |= (0x3 << GPIO_PD_18);
    printf("##################### %08x ####################\n", *pd_data_reg);

    printf("DRV0 REG:\n");
    printf("##################### %08x ####################\n", *pd_drv0_reg);
    *pd_drv0_reg &= 0x00;
    *pd_drv0_reg |= 0x10000;
    printf("##################### %08x ####################\n", *pd_drv0_reg);

    printf("DRV1 REG:\n");
    printf("##################### %08x ####################\n", *pd_drv1_reg);
    *pd_drv1_reg &= 0x00;
    *pd_drv1_reg |= 0x50;
    printf("##################### %08x ####################\n", *pd_drv1_reg);

    printf("PULL0 REG:\n");
    printf("##################### %08x ####################\n", *pd_pull0_reg);
    *pd_pull0_reg &= 0x00;
    *pd_pull0_reg |= 0x10000;
    printf("##################### %08x ####################\n", *pd_pull0_reg);

    printf("PULL1 REG:\n");
    printf("##################### %08x ####################\n", *pd_pull1_reg);
    *pd_pull1_reg &= 0x00;
    *pd_pull1_reg |= 0x50;
    printf("##################### %08x ####################\n", *pd_pull1_reg);


    close(mem_fd);
    munmap(gpio, MAP_SIZE);

    return 0;
}

注意的问题:

  1. mmap 映射SIZE必须为页大小的整数倍,这里取值4096刚好等于页大小。
  2. mmap返回值为void *类型,通过类似以下代码
    pd_cfg1_reg = gpio + PD_CFG_REG_1_OFFSET;
    进行了类型转换为unsigned int *类型。
  3. mmap函数的最后一个参数是
    GPIO_LED_BASE_ADDR & ~MAP_MASK
    所以寄存器地址得这样算
    #define PD_CFG_REG_1_OFFSET ((GPIO_LED_BASE_ADDR & MAP_MASK) + 0x0070)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式Linux中,可以使用C语言编写程序来读写GPIO。以下是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define GPIO_ADDR_BASE 0x40000000 // GPIO基地址 #define GPIO_PIN_NUM 1 // GPIO引脚编号 int main(int argc, char *argv[]) { int fd; void *gpio_base; volatile unsigned int *gpio_data; // 打开/dev/mem设备 fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { perror("open"); exit(1); } // 映射GPIO基地址 gpio_base = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_ADDR_BASE); if (gpio_base == MAP_FAILED) { perror("mmap"); exit(1); } // 获取GPIO引脚的数据寄存器地址 gpio_data = (volatile unsigned int *)((unsigned int)gpio_base + GPIO_PIN_NUM * 4); // 设置GPIO引脚为输出模式 *gpio_data &= ~(1 << GPIO_PIN_NUM); // 输出高电平 *gpio_data |= 1 << GPIO_PIN_NUM; // 输出低电平 *gpio_data &= ~(1 << GPIO_PIN_NUM); // 释放GPIO基地址映射 munmap(gpio_base, 0x1000); // 关闭/dev/mem设备 close(fd); return 0; } ``` 以上示例代码使用了/dev/mem设备来访问GPIO,需要进行root权限运行。该示例代码通过映射GPIO基地址,获取GPIO引脚的数据寄存器地址,然后通过设置数据寄存器的位来控制GPIO引脚的电平。具体来说,通过设置数据寄存器的特定位为1可以输出高电平,通过设置数据寄存器的特定位为0可以输出低电平。在代码中,GPIO_PIN_NUM表示GPIO引脚的编号,可以根据需要修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值