ARM-Linux应用程序读写GPIO

问题背景

我们在做嵌入式开发时常需要从应用程序中读取某个GPIO端口,这些端口往往连接了其他的板子,或外设。
那么解决问题的办法有两种。

写驱动

  1. 编写一个linux驱动
  2. 加载到内核中
  3. 应用程序通过读取驱动生成的虚拟文件来读写GPIO

这种做法实在有些麻烦。

第二种方法 mmap

了解到这种方法的起因是 在阅读相关树莓派的资料时,发现人家居然可以用python访问gpio口!!
看了它的C实现版本。弄明白了!


#include 
#include 

int main(int argc, char **argv)
{
    if (geteuid() == 0)
    {
    if (!bcm2835_init())
        return 1;
    if (!bcm2835_close())
        return 1;
    }
    else
    {
    fprintf(stderr, "****You need to be root to properly run this test program\n");
    }
    return 0;
}

下载了这个类库的源码发现init中写到


    if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) 
    {
    fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n",
        strerror(errno)) ;
    goto exit;
    }

....
bcm2835_gpio = (volatile uint32_t *)mapmem("gpio", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_BASE);

而mapmem中写到:

static void *mapmem(const char *msg, size_t size, int fd, off_t off)
{
    void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off);
    if (MAP_FAILED == map)
    fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
    return map;
}

一切就明白了。
1. 打开/dev/mem 这个特殊的设备
2. mmap映射。
3. 访问映射后的内存即可
那么GPIO对应的内存地址是多少呢? 这个要看文档了。对于树莓派来说:

#define BCM2835_PERI_BASE               0x20000000
/// Base Physical Address of the System Timer registers
#define BCM2835_ST_BASE         (BCM2835_PERI_BASE + 0x3000)
/// Base Physical Address of the Pads registers
#define BCM2835_GPIO_PADS               (BCM2835_PERI_BASE + 0x100000)
/// Base Physical Address of the Clock/timer registers
#define BCM2835_CLOCK_BASE              (BCM2835_PERI_BASE + 0x101000)
/// Base Physical Address of the GPIO registers
#define BCM2835_GPIO_BASE               (BCM2835_PERI_BASE + 0x200000)
/// Base Physical Address of the SPI0 registers
#define BCM2835_SPI0_BASE               (BCM2835_PERI_BASE + 0x204000)
/// Base Physical Address of the BSC0 registers
#define BCM2835_BSC0_BASE       (BCM2835_PERI_BASE + 0x205000)
/// Base Physical Address of the PWM registers
#define BCM2835_GPIO_PWM                (BCM2835_PERI_BASE + 0x20C000)
 /// Base Physical Address of the BSC1 registers
#define BCM2835_BSC1_BASE       (BCM2835_PERI_BASE + 0x804000)

你可能感兴趣的:(嵌入式开发)