mmap操作荔枝派gpio v3s Linux
转至https://blog.csdn.net/diqiyong3212/article/details/102053091
1.预备知识
https://baike.baidu.com/item/mmap/1322217?fr=aladdin 大家直接看百度百科,比较清楚了。
2.代码
gpio.c
#include "gpio.h"
unsigned int fd;
PIO_Map *PIO = NULL;
unsigned int *gpio_map;
unsigned int addr_start, addr_offset;
unsigned int PageSize, PageMask;
void GPIO_Init(void)
{
if ((fd = open("/dev/mem", O_RDWR)) == -1)
{
printf("open error\r\n");
return;
}
PageSize = sysconf(_SC_PAGESIZE); //使用sysconf查询系统页面大小
PageMask = (~(PageSize - 1)); //页掩码
printf("PageSize:%d,PageMask:0x%.8X\r\n", PageSize, PageMask);
addr_start = PIO_BASE_ADDRESS & PageMask; //0x01C20800 & 0xfffff000 = 0x1C20000
addr_offset = PIO_BASE_ADDRESS & ~PageMask; //0x01C20800 & 0x00000100 = 0x800
printf("addr_start:%.8X,addr_offset:0x%.8X\r\n", addr_start, addr_offset);
//mmap(系统自动分配内存地址,映射区长度“内存页的整数倍”,选择可读可写,MAP_SHARED=与其他所有映射到这个对象的进程共享空间,文件句柄,被映射内容的起点)
//offest 映射物理内存的话,必须页对其!!! 所以这个起始地址应该是0x1000的整数倍,那么明显0x01C20800需要减去0x800才是整数倍!
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);
//这里已经将0x1c20000的地址映射到了内存中,但是我们需要的地址是0x01C20800,所以要再加上地址偏移量~
PIO = (PIO_Map *)((unsigned int)gpio_map + addr_offset);
printf("PIO:0x%.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);
printf("struct PIO_Struct size : %d",sizeof(PIO->Pn[port]));
}
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);
}
int GPIO_Free(void)
{
if ((munmap(gpio_map, PageSize * 2)) == 0)//取消映射
{
printf("unmap success!\r\n");
}
else
{
printf("unmap failed!\r\n");
}
return 0;
}
gpio.h
#ifndef __GPIO_H__
#define __GPIO_H__
#include
#include
#include
#include
#include
#include
#define PIO_BASE_ADDRESS 0x01C20800
//unsigned int 4字节 一个PIO_Struct占36字节,对应十六进制就是0x24,正好是一个offset值。
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);
int GPIO_Free(void);
#endif
main.c
#include
#include
#include
#include
#include
#include
#include "gpio.h"
#include
int main()
{
int a=0,b=-1,i;
GPIO_Init();
GPIO_ConfigPin(PB,4,OUT);
GPIO_ConfigPin(PB,5,OUT);
for(i=0;i<20;i++)
{
GPIO_SetPin(PB,4,a=~a);//!!-1的取反是0 1的取反是-2....
GPIO_SetPin(PB,5,b=~b);
//usleep(100000);
sleep(1);
}
GPIO_Free();
}
makefile
TARGET = myGPIO #可执行文件名称
########################编译参数############################
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
DEFINES =
CFLAGS = -pipe -g -Wall -W -fPIE $(DEFINES)
CXXFLAGS = -pipe -g -Wall -W -fPIE $(DEFINES)
INCPATH = -I.
########################编译文件############################
SOURCES = ./main.c ./gpio.c
OBJECTS = main.o gpio.o
$(TARGET) : $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)
main.o : main.c gpio.h
$(CC) $(include) $(CFLAGS) -c main.c
gpio.o : gpio.c gpio.h
$(CC) $(include) $(CFLAGS) -c gpio.c
clean :
rm $(OBJECTS) $(TARGET)
3.运行
将程序编译出来放到v3s上运行,那么pb4 pb5 会交替高低电平。