目的:应用层快捷、方便的配置gpio
gpio获取步骤:
1 管脚复用
2 获取gpio方向和值
gpio配置步骤:
1 管脚复用
2 配置gpio方向
3 如果是输出方向,可以配置gpio值
typedef struct _tagPINMUX_REG_S
{
HI_U32 u32Reg;
HI_U32 u32Val;
}PINMUX_REG_S;
HI_S32 HI_GPIOMNG_Init(PINMUX_REG_S *paPinmuxReg, HI_U8 u8PinmuxRegSize);
HI_S32 HI_GPIOMNG_Denit();
HI_S32 HI_GPIOMNG_SetDir(HI_U8 u8Gpio, HI_U8 u8Dir);
HI_S32 HI_GPIOMNG_GetDir(HI_U8 u8Gpio);
HI_S32 HI_GPIOMNG_SetVal(HI_U8 u8Gpio, HI_U8 u8Val);
HI_S32 HI_GPIOMNG_GetVal(HI_U8 u8Gpio);
HI_GPIOMNG_Init:管脚复用和gpio寄存器地址映射到应用层
HI_GPIOMNG_Denit:关闭gpio寄存器地址映
HI_GPIOMNG_SetDir:配置gpio方向(0输入,1输出)
HI_GPIOMNG_GetDir:获取gpio方向(0输入,1输出)
HI_GPIOMNG_SetVal:配置gpio值(0 低,1 高)
HI_GPIOMNG_GetVal:获取gpio值(0 低,1 高)
u8Gpio:海思gpio号计算公式:u8Gpio=GpioGroup*8+GpioBit
#include
#include
#include
#include
#include
#include
#include
#include
#include "hi_type.h"
#include "hi_gpiomng.h"
#define GPIO_BASE_ADDR (0x120D0000)
#define GPIO_GRP(group_id) (g_pGpioBaseAddr+0x1000*group_id)
#define GPIO_DATA(group_reg_base, gpio_offset) (((group_reg_base) + 0x000) + (1 << ((gpio_offset) + 2)))
#define GPIO_DIR(group_reg_base) ((group_reg_base) + 0x400)
#define GPIO_IS(group_reg_base) ((group_reg_base) + 0x404)
#define GPIO_IBE(group_reg_base) ((group_reg_base) + 0x408)
#define GPIO_IEV(group_reg_base) ((group_reg_base) + 0x40C)
#define GPIO_IE(group_reg_base) ((group_reg_base) + 0x410)
#define GPIO_RIS(group_reg_base) ((group_reg_base) + 0x414)
#define GPIO_MIS(group_reg_base) ((group_reg_base) + 0x418)
#define GPIO_IC(group_reg_base) ((group_reg_base) + 0x41C)
#define PAGE_SIZE_MASK (~(0xfff))
#define PAGE_SIZE 0x1000
#define GPIO_MAP_MEM_SIZE 0xC000
static const char dev[]="/dev/mem";
static HI_VOID *g_pGpioBaseAddr = NULL;
static HI_BOOL g_bGpioInit = HI_FALSE;
HI_VOID * COMM_MMAP(HI_U32 u32RetAddr, HI_U32 u32MapMemSize)
{
HI_S32 fd = open (dev, O_RDWR | O_SYNC);
if (fd < 0)
{
printf("open %s error!\n", dev);
return NULL;
}
/* addr align in page_size(4K) */
unsigned long phy_addr_in_page;
unsigned long page_diff;
phy_addr_in_page = u32RetAddr & PAGE_SIZE_MASK;
page_diff = u32RetAddr - phy_addr_in_page;
/* size in page_size */
unsigned long size_in_page;
unsigned long size = u32MapMemSize;
size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE;
void *addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
if (addr == MAP_FAILED)
{
printf("mmap @ 0x%x error!\n", phy_addr_in_page);
close(fd);
return NULL;
}
close(fd);
return addr+page_diff;
}
HI_VOID COMM_MUNMAP(HI_VOID *pRegAddr, HI_U32 u32MapMemSize)
{
munmap(pRegAddr, u32MapMemSize);
}
HI_S32 HI_GPIOMNG_Init(PINMUX_REG_S *paPinmuxReg, HI_U8 u8PinmuxRegSize)
{
HI_S32 s32Ret;
HI_S32 i;
// PINMUX
for(i = 0; i < u8PinmuxRegSize; i++)
{
HI_VOID *pRegAddr = COMM_MMAP(paPinmuxReg[0].u32Reg, PAGE_SIZE);
if(pRegAddr)
{
// 判断功能位, 这样可以保护以前已经复用过且配置好的管脚高低状态
if((*((HI_U32 *)pRegAddr)&0x0f) != (paPinmuxReg[0].u32Val&0x0f))
{
*((HI_U32 *)pRegAddr) = paPinmuxReg[0].u32Val;
}
COMM_MUNMAP(pRegAddr, PAGE_SIZE);
}
else
{
printf("gpio pinmux failed!");
return HI_FAILURE;
}
}
// MAP GPIO_BASE
g_pGpioBaseAddr = COMM_MMAP(GPIO_BASE_ADDR, GPIO_MAP_MEM_SIZE);
if(g_pGpioBaseAddr == NULL)
{
printf("gpio map failed!");
return HI_FAILURE;
}
g_bGpioInit = HI_TRUE;
return HI_SUCCESS;
}
HI_S32 HI_GPIOMNG_Denit()
{
if(g_bGpioInit)
{
COMM_MUNMAP(g_pGpioBaseAddr, GPIO_MAP_MEM_SIZE);
g_bGpioInit = HI_FALSE;
}
return HI_SUCCESS;
}
HI_S32 HI_GPIOMNG_SetDir(HI_U8 u8Gpio, HI_U8 u8Dir)
{
if(!g_bGpioInit) return HI_FAILURE;
HI_U8 u8GpioGroup;
HI_U8 u8GpioBit;
HI_VOID *pGroupAddr;
HI_VOID *pDirAddr;
u8GpioGroup = u8Gpio/8;
u8GpioBit = u8Gpio%8;
pGroupAddr = GPIO_GRP(u8GpioGroup);
pDirAddr = GPIO_DIR(pGroupAddr);
if(u8Dir)
{
*(HI_U32 *)pDirAddr |= (0x1<<u8GpioBit);
}
else
{
*(HI_U32 *)pDirAddr &= ~(0x1<<u8GpioBit);
}
return HI_SUCCESS;
}
HI_S32 HI_GPIOMNG_GetDir(HI_U8 u8Gpio)
{
if(!g_bGpioInit) return HI_FAILURE;
HI_U8 u8GpioGroup;
HI_U8 u8GpioBit;
HI_VOID *pGroupAddr;
HI_VOID *pDirAddr;
u8GpioGroup = u8Gpio/8;
u8GpioBit = u8Gpio%8;
pGroupAddr = GPIO_GRP(u8GpioGroup);
pDirAddr = GPIO_DIR(pGroupAddr);
if((*(HI_U32 *)pDirAddr)&(0x1<<u8GpioBit))
{
return 1;
}
else
{
return 0;
}
}
HI_S32 HI_GPIOMNG_SetVal(HI_U8 u8Gpio, HI_U8 u8Val)
{
if(!g_bGpioInit) return HI_FAILURE;
HI_U8 u8GpioGroup;
HI_U8 u8GpioBit;
HI_VOID *pGroupAddr;
HI_VOID *pDataAddr;
u8GpioGroup = u8Gpio/8;
u8GpioBit = u8Gpio%8;
pGroupAddr = GPIO_GRP(u8GpioGroup);
pDataAddr = GPIO_DATA(pGroupAddr, u8GpioBit);
if(u8Val)
{
*(HI_U32 *)pDataAddr |= (0x1<<u8GpioBit);
}
else
{
*(HI_U32 *)pDataAddr &= ~(0x1<<u8GpioBit);
}
return HI_SUCCESS;
}
HI_S32 HI_GPIOMNG_GetVal(HI_U8 u8Gpio)
{
if(!g_bGpioInit) return HI_FAILURE;
HI_U8 u8GpioGroup;
HI_U8 u8GpioBit;
HI_VOID *pGroupAddr;
HI_VOID *pDataAddr;
u8GpioGroup = u8Gpio/8;
u8GpioBit = u8Gpio%8;
pGroupAddr = GPIO_GRP(u8GpioGroup);
pDataAddr = GPIO_DATA(pGroupAddr, u8GpioBit);
if((*(HI_U32 *)pDataAddr)&(0x1<<(u8GpioBit+2)))
{
return 1;
}
else
{
return 0;
}
return HI_SUCCESS;
}
测试(有LED等的测试结果可以验证):
/app # ./hi_debug -r -g 4
Get: GPIO[4] DIR[OUT] DATA[0]
/app # ./hi_debug -w -g 4 -D 0
Set Dir: GPIO[4] DIR[IN]
/app # ./hi_debug -w -g 4 -D 1
Set Dir: GPIO[4] DIR[OUT]
/app # ./hi_debug -w -g 4 -d 0
Set Data: GPIO[4] DIR[OUT] DATA[0]
/app # ./hi_debug -w -g 4 -d 1
Set Data: GPIO[4] DIR[OUT] DATA[1]
改进:
可以添加一个参数-c/–config, 用于提前配置管脚复用信息,可以更加灵活。
准备基于gpio接口函数实现一个调试小工具,该工具具备以下功能:
准备工作:
根据Hi35xx_PINOUT_CN.xls,列出开发板上应用会用到的gpio,用于HI_GPIOMNG_Init函数初始化gpio管脚复用。
其他方向:
#include
#include
#include
#include
#include "hi_type.h"
#include "hi_gpiomng.h"
static const char *short_options = "hrwg:D:d:";
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"read", 0, 0, 'r'}, //
{"write", 0, 0, 'w'}, //
{"gpio", 1, 0, 'g'}, //
{"dir", 1, 0, 'D'}, //
{"data", 1, 0, 'd'}, //
{0, 0, 0, 0}
};
static PINMUX_REG_S pinux_regs[] = {
{0x112f0098, 0x0500}, // GPIO0_4
{0x112F0008, 0x0500}, // GPIO6_0
{0x112F000C, 0x0500}, // GPIO6_1
{0x112F0010, 0x0500}, // GPIO6_2
};
static void usage(int argc, char *argv[])
{
printf("The program is uesed to read/write gpio[ build by wei on %s ].\n", __DATE__);
printf("usage: %s [OPTION]...\n", argv[0]);
printf("\t-h, --help help\n"
"\t-r, --read read gpio\n"
"\t-w, --write write gpio\n"
"\t-g, --gpio gpio number(gpio_group*8+gpio_bit)\n"
"\t-D, --dir gpio direction(0[in] or 1[out]\n"
"\t-d, --data gpio data(0 or 1)\n");
printf("Example:\n");
printf(" --- Default: %s -r -g 4\n", argv[0]);
printf(" %s -w -g 4 -d 1\n", argv[0]);
printf(" %s -w -g 4 -D 0\n", argv[0]);
printf("\n");
}
int main(int argc, char *argv[])
{
int option_index, ch;
int read = 0;
int write = 0;
int gpio = 0;
int data = 0;
int data_flag = 0;
int dir = 0;
int dir_flag = 0;
while ((ch = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
switch (ch) {
case 'h':
usage(argc, argv);
return 0;
case 'r':
read = 1;
break;
case 'w':
write = 1;
break;
case 'g':
if(strchr(optarg, 'X') || strchr(optarg, 'x'))
{
gpio = strtol(optarg, NULL, 16);
}
else
{
gpio = strtol(optarg, NULL, 10);
}
break;
case 'D':
dir_flag = 1;
if(strchr(optarg, 'X') || strchr(optarg, 'x'))
{
dir = strtol(optarg, NULL, 16)?1:0;
}
else
{
dir = strtol(optarg, NULL, 10)?1:0;
}
break;
case 'd':
data_flag = 1;
if(strchr(optarg, 'X') || strchr(optarg, 'x'))
{
data = strtol(optarg, NULL, 16)?1:0;
}
else
{
data = strtol(optarg, NULL, 10)?1:0;
}
break;
default:
printf("Try '--help' for more information.\n");
return 1;
}
}
if(optind <= argc-1);
if(read)
{
HI_GPIOMNG_Init(pinux_regs, sizeof(pinux_regs)/sizeof(pinux_regs[0]));
int gpioDir = HI_GPIOMNG_GetDir(gpio);
int gpioDat = HI_GPIOMNG_GetVal(gpio);
printf("Get: GPIO[%d] DIR[%s] DATA[%d]\n", gpio, gpioDir?"OUT":"IN", gpioDat);
HI_GPIOMNG_Denit();
}
else if(dir_flag)
{
HI_GPIOMNG_Init(pinux_regs, sizeof(pinux_regs)/sizeof(pinux_regs[0]));
HI_GPIOMNG_SetDir(gpio, dir);
if(data_flag)
{
HI_GPIOMNG_SetVal(gpio, data);
printf("Set Dir: GPIO[%d] DIR[%s] DATA[%d]\n", gpio, dir?"OUT":"IN", data);
}
else
{
printf("Set Dir: GPIO[%d] DIR[%s]\n", gpio, dir?"OUT":"IN");
}
HI_GPIOMNG_Denit();
}
else if(write)
{
HI_GPIOMNG_Init(pinux_regs, sizeof(pinux_regs)/sizeof(pinux_regs[0]));
HI_GPIOMNG_SetDir(gpio, 1);
HI_GPIOMNG_SetVal(gpio, data);
printf("Set Data: GPIO[%d] DIR[%s] DATA[%d]\n", gpio, "OUT", data);
HI_GPIOMNG_Denit();
}
else
{
usage(argc, argv);
}
return 0;
}
#比如配置gpio0_4为输出,拉高
himm 0x112f0098 0x0500
himm 0x120d0400 0x10
himm 0x120d0040 0x10
#比如配置gpio0_4为输出,拉高
echo 4 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio4/direction
echo 1 > /sys/class/gpio/gpio4/value
echo 4 > /sys/class/gpio/unexport
通用所有海思(有linux内核的)
hi_gpiomng