使用/dev/mem記憶體對映的方式操做GPIO口
阿新 • • 發佈:2020-09-13
使用的是全志H3的晶片,執行Debian Desktop系統的ARM版本Armbian,要控制外部幾個IO口,能夠使用不少種方法,若是對GPIO的操做速度有要求就須要使用直接操做記憶體暫存器的方式來控制GPIO口。AllWinner的官方資料手冊文件上介紹了GPIO的暫存器內容:函式
GPIO暫存器對映表spa
GPIO配置暫存器code
GPIO的暫存器在記憶體的基地址是0x01C20800,因此要將0x01C20800以後的內容對映到程序的虛擬記憶體之中,使用的mmap函式,這個函式的使用有很多限制,好比最後一個引數offset的意思是要被對映的實體記憶體地址偏移量,好比這裡就是0x01C20800,可是要求這個offset必須是頁大小的整倍數,因此這裡0x01C20800
下面是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); #pio_ase_address 暫存器實體地址 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_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();
}