zoukankan      html  css  js  c++  java
  • 使用/dev/mem内存映射的方式操做GPIO口

    使用的是全志H3的芯片,运行Debian Desktop系统的ARM版本Armbian,要控制外部几个IO口,能够使用不少种方法,若是对GPIO的操做速度有要求就须要使用直接操做内存寄存器的方式来控制GPIO口。AllWinner的官方数据手册文档上介绍了GPIO的寄存器内容:函数

    GPIO寄存器映射表spa

    GPIO配置寄存器code

    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
    ");
    		return;
    	}
    
    	PageSize = sysconf(_SC_PAGESIZE);	//页大小
    	PageMask = (~(PageSize-1));			//页掩码
    	printf("PageSize:%d,PageMask:%.8X
    ",PageSize,PageMask);
    #pio_ase_address 寄存器物理地址
    	addr_start = PIO_BASE_ADDRESS & PageMask;
    	addr_offset = PIO_BASE_ADDRESS & ~PageMask;
    	printf("addr_start:%.8X,addr_offset:%.8X
    ",addr_start,addr_offset);
    
    	if((gpio_map = mmap(NULL,PageSize*2,PROT_READ|PROT_WRITE, MAP_SHARED,fd,addr_start)) == NULL)
    	{
    		printf("mmap error
    ");
    		close(fd);
    		return;
    	}
    	printf("gpio_map:%.8X
    ",gpio_map);
    
    	PIO = (PIO_Map *)((unsigned int)gpio_map + addr_offset);
    	printf("PIO:%.8X
    ",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_ADDRESS	0x01C20800
    
    	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();
    }
    

     

  • 相关阅读:
    ThinkPHP框架返回插入记录的id号
    TP框架中关于if、else 分支结构逻辑错误
    SVN 快速入门!
    TP框架中如何使用SESSION限制登录?
    TP框架M方法 create方法丢失字段问题
    .NET Framework 工具
    X86-64寄存器和栈帧
    微软开源资源 NET Foundation Projects
    Import 元素 (MSBuild)
    C#开源资源项目
  • 原文地址:https://www.cnblogs.com/dream397/p/13658967.html
Copyright © 2011-2022 走看看