45fan.com - 路饭网

搜索: 您的位置主页 > 网络频道 > 阅读资讯:使用/dev/mem内存映射的方式操作GPIO口

使用/dev/mem内存映射的方式操作GPIO口

2019-03-30 18:36:15 来源:www.45fan.com 【

使用的是全志H3的芯片,运行Debian Desktop系统的ARM版本Armbian,要控制外部几个IO口,可以使用很多种方法,如果对GPIO的操作速度有要求就需要使用直接操作内存寄存器的方式来控制GPIO口。AllWinner的官方数据手册文档上介绍了GPIO的寄存器内容:

使用/dev/mem内存映射的方式操作GPIO口使用/dev/mem内存映射的方式操作GPIO口使用/dev/mem内存映射的方式操作GPIO口

GPIO寄存器映射表

使用/dev/mem内存映射的方式操作GPIO口使用/dev/mem内存映射的方式操作GPIO口使用/dev/mem内存映射的方式操作GPIO口

GPIO配置寄存器

GPIO的寄存器在内存的基地址是0x01C20800,所以要将0x01C20800之后的内容映射到进程的虚拟内存之中,使用的mmap函数,这个函数的使用有不少限制,比如最后一个参数offset的意思是要被映射的物理内存地址偏移量,比如这里就是0x01C20800,但是要求这个offset必须是页大小的整倍数,所以这里0x01C20800并不能直接作为offset值,需要向前截取到为页大小整倍数的地址,然后在映射后的虚拟地址上加上多余的偏移量,具体程序执行如下面的GPIO_Init函数中的操作方法。

下面是gpio.c文件的内容:

#include "gpio.h" 

PIO_Map *PIO = NULL;
unsigned int *gpio_map;

void GPIO_Init(void)
{
unsigned int fd;
unsigned int addr_start, addr_offset;
unsigned int PageSize, PageMask;

if((fd = open("/dev/mem",O_RDWR)) == -1)
{
printf("open error\r\n");
return;
}

PageSize = sysconf(_SC_PAGESIZE);//页大小
PageMask = (~(PageSize-1));//页掩码
printf("PageSize:%d,PageMask:%.8X\r\n",PageSize,PageMask);

addr_start = PIO_BASE_ADDRESS & PageMask;
addr_offset = PIO_BASE_ADDRESS & ~PageMask;
printf("addr_start:%.8X,addr_offset:%.8X\r\n",addr_start,addr_offset);

if((gpio_map = mmap(NULL,PageSize*2,PROT_READ|PROT_WRITE, MAP_SHARED,fd,addr_start)) == NULL)
{
printf("mmap error\r\n");
close(fd);
return;
}
printf("gpio_map:%.8X\r\n",gpio_map);

PIO = (PIO_Map *)((unsigned int)gpio_map + addr_offset);
printf("PIO:%.8X\r\n",PIO);

close(fd);
}

void GPIO_ConfigPin(PORT port,unsigned int pin,PIN_MODE mode)
{
  if (gpio_map == NULL)
    return;
PIO->Pn[port].CFG[pin / 8] &= ~((unsigned int)0x07 << pin % 8 * 4);
PIO->Pn[port].CFG[pin / 8] |= ((unsigned int)mode << pin % 8 * 4);
}

void GPIO_SetPin(PORT port,unsigned int pin,unsigned int level)
{
  if (gpio_map == NULL)
    return;
if(level)
PIO->Pn[port].DAT |= (1 << pin);
else
PIO->Pn[port].DAT &= ~(1 << pin);
}

下面是gpio.h文件:

#ifndef __GPIO_H__
#define __GPIO_H__
#include<stdio.h> 
#include<unistd.h> 
#include<sys/mman.h> 
#include<sys/types.h> 
#include<sys/stat.h> 
#include<fcntl.h> 

#define PIO_BASE_ADDRESS0x01C20800

typedef struct
{
unsigned int CFG[4];
unsigned int DAT ;
unsigned int DRV0;
unsigned int DRV1;
unsigned int PUL0;
unsigned int PUL1;
}PIO_Struct;

typedef struct
{
PIO_Struct Pn[7];
}PIO_Map;

typedef enum
{
PA = 0,
PB = 1,
PC = 2,
PD = 3,
PE = 4,
PF = 5,
PG = 6,
}PORT;

typedef enum
{
IN= 0x00,
OUT= 0x01,
AUX= 0x02,
INT= 0x06,
DISABLE= 0x07,
}PIN_MODE;

extern PIO_Map *PIO;

void GPIO_Init(void);
void GPIO_ConfigPin(PORT port,unsigned int pin,PIN_MODE mode);
void GPIO_SetPin(PORT port,unsigned int pin,unsigned int level);
unsigned int GPIO_GetPin(PORT port,unsigned int pin);
void GPIO_Free(void);
#endif
主文件main.c如下:
#include<stdio.h> 
#include<unistd.h> 
#include<sys/mman.h> 
#include<sys/types.h> 
#include<sys/stat.h> 
#include<fcntl.h> 
#include "gpio.h" 

int main()
{
GPIO_Init();

int a = 0;
GPIO_ConfigPin(PA,15,OUT);
while(1)
{
GPIO_SetPin(PA,15,a = ~a);
usleep(100000);
}

GPIO_Free();
}


 
 

本文地址:http://www.45fan.com/a/question/100060.html
Tags: 内存 mem dev
编辑:路饭网
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部