apple_eat 发表于 2016-12-1 15:04:07

树莓派外设直接编程驱动

目前树莓派python版本的硬件驱动库只能使用GPIO,SPI等,很多外设的功能都没办法用.
可以使用mmap映射物理地址,直接操作外设的寄存器,这样树莓派的整个硬件资源就可以打通了.下面是通过操作GPIO寄存器控制一个引脚的例子,其他的外设也可以参照操作.


#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

#include <fcntl.h>                // 文件打开、加锁等操作
#include <unistd.h>                // unistd.h 是 C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的头文件的名称。是Unix Standard的缩写。
#include <errno.h>                // errno.h是C语言C标准库里的头文件,定义了通过错误码来回报错误信息的宏:

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>        // 内存管理,包括POSIX 共享内存 (进程间通信)与内存映射文件

#define PERIPH_BASE_RPI2        0x3F000000
#define GPIO_OFFSET                        0x00200000

typedef struct
{
        uint32_t fsel;                            // GPIO Function Select
        uint32_t resvd_0x18;
        uint32_t set;                           // GPIO Pin Output Set
        uint32_t resvd_0x24;
        uint32_t clr;                           // GPIO Pin Output Clear
        uint32_t resvd_0x30;
        uint32_t lev;                           // GPIO Pin Level
        uint32_t resvd_0x3c;
        uint32_t eds;                           // GPIO Pin Event Detect Status
        uint32_t resvd_0x48;
        uint32_t ren;                           // GPIO Pin Rising Edge Detect Enable
        uint32_t resvd_0x54;
        uint32_t fen;                           // GPIO Pin Falling Edge Detect Enable
        uint32_t resvd_0x60;
        uint32_t hen;                           // GPIO Pin High Detect Enable
        uint32_t resvd_0x6c;
        uint32_t len;                           // GPIO Pin Low Detect Enable
        uint32_t resvd_0x78;
        uint32_t aren;                            // GPIO Pin Async Rising Edge Detect
        uint32_t resvd_0x84;
        uint32_t afen;                            // GPIO Pin Async Falling Edge Detect
        uint32_t resvd_0x90;
        uint32_t pud;                              // GPIO Pin Pull up/down Enable
        uint32_t pudclk;                        // GPIO Pin Pull up/down Enable Clock
        uint32_t resvd_0xa0;
        uint32_t test;
} __attribute__((packed, aligned(4))) gpio_t;

volatile gpio_t * gpio;

void GPIO_WriteHigh(gpio_t * gpio, int pin)
{
        if (pin > 53)
                return;
        int reg = pin >> 5;
        int offset = (pin & 0x1F);
        gpio->set |= (1 << offset);
}

void GPIO_WriteLow(gpio_t * gpio, int pin)
{
        if (pin > 53)
                return;
        int reg = pin / 32;
        int offset = pin % 32;
        gpio->clr |= (1 << offset);
}

typedef enum
{
        GPIO_Function_Input = 0,
        GPIO_Function_Output = 1,
        GPIO_Function_Alternate0 = 2,
        GPIO_Function_Alternate1 = 3,
        GPIO_Function_Alternate2 = 4,
        GPIO_Function_Alternate3 = 5,
        GPIO_Function_Alternate4 = 6,
        GPIO_Function_Alternate5 = 7
}GPIO_FUNCTION_SEL;

void GPIO_SetMode(gpio_t * gpio, int pin, GPIO_FUNCTION_SEL sel)
{
        if (pin > 53)
                return;
        int reg = pin / 10;
        int offset = (pin % 10) * 3;
        gpio->fsel &= ~(0x00000007 << offset);
        gpio->fsel |= (sel << offset);
}


int main(int argc, char * argv[])
{
        int mem_fd;

        mem_fd = open("/dev/mem", O_RDWR);
        if (mem_fd == -1)
        {
                perror("mem");
                exit(0);
        }

        gpio = mmap(0, sizeof(gpio_t), PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, (PERIPH_BASE_RPI2 + GPIO_OFFSET));
        if (gpio == MAP_FAILED)
        {
                perror("mmap");
                exit(0);
        }

        GPIO_SetMode(gpio, 18, GPIO_Function_Output);

        while (true)
        {
                GPIO_WriteHigh(gpio, 18);
                sleep(1);
                GPIO_WriteLow(gpio, 18);
                sleep(1);
        }

        return 0;
}

four_zhg 发表于 2016-12-1 15:56:38

不错,这样的话,其它端口就也可以使用了

apple_eat 发表于 2016-12-1 16:26:36

four_zhg 发表于 2016-12-1 15:56
不错,这样的话,其它端口就也可以使用了

还可以通过DMA+PWM的方式直接驱动ws2812b,
Github上有一个项目https://github.com/jgarff/rpi_ws281x

XIVN1987 发表于 2016-12-1 16:52:59

Python也可以{:lol:}{:lol:}

wxws_wxws 发表于 2016-12-1 17:53:52

哈,终于有人聊树莓派了

TIANYJ 发表于 2016-12-1 18:27:38

这个消息真是太好了,可以直接调试外设。

NJ8888 发表于 2016-12-1 19:02:46

几年前就用mmap操作linux下硬件,不知道树莓的寄存器手册是否详细?一直没玩

hexenzhou 发表于 2016-12-1 19:50:21

不错,支持一下。我的PI3快长灰了。

chinazhaoyl 发表于 2016-12-1 20:04:13

好,空闲时候玩玩

fengyunyu 发表于 2016-12-1 20:49:58

mmap方式,很多人都这样搞!

apple_eat 发表于 2016-12-2 08:53:22

XIVN1987 发表于 2016-12-1 16:52
Python也可以

这个还真没了解过,python功能挺强大的呀.

genhao2 发表于 2016-12-3 07:14:27

python类库很多
页: [1]
查看完整版本: 树莓派外设直接编程驱动