0 前言
本文描述如果通过文件IO sysfs方式控制3516 GPIO端口。通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO方向,而value可控制GPIO输出或获得GPIO输入。
用户空间访问gpio,即通过sysfs接口访问gpio,下面是/sys/class/gpio目录下的三种文件:
—export/unexport文件
—gpioN指代具体的gpio引脚
—gpio_chipN指代gpio控制器
开始之前,首先看看系统中有没有“/sys/class/gpio”这个文件夹。
如果没有请在编译内核的时候加入 Device Drivers —> GPIO Support —> /sys/class/gpio/… (sysfs interface)
(1) export/unexport文件接口:
/sys/class/gpio/export,该接口只能写不能读。
用户程序通过写入gpio的编号来向内核申请将某个gpio的控制权导出到用户空间
比如 echo 19 > export
上述操作会为19号gpio创建一个节点gpio19,此时/sys/class/gpio目录下边生成一个gpio19的目录
/sys/class/gpio/unexport和导出的效果相反。
比如 echo 19 > unexport
上述操作将会移除gpio19这个节点。
(2) /sys/class/gpio/gpioN
指代某个具体的gpio端口,里边有如下属性文件
direction 表示gpio端口的方向,读取结果是in或out。该文件也可以写,写入out 时该gpio设为输出同时电平默认为低。写入low或high则不仅可以设置为输出 还可以设置输出的电平。 当然如果内核不支持或者内核代码不愿意,将不会存在这个属性,比如内核调用了gpio_export(N,0)就表示内核不愿意修改gpio端口方向属性 。
value 表示gpio引脚的电平,0(低电平)1(高电平),如果gpio被配置为输出,这个值是可写的,记住任何非零的值都将输出高电平, 如果某个引脚能并且已经被配置为中断,则可以调用poll(2)函数监听该中断,中断触发后poll(2)函数就会返回。
edge 表示中断的触发方式,edge文件有如下四个值:”none”, “rising”, “falling”,”both”。
none 表示引脚为输入,不是中断引脚;
rising 表示引脚为中断输入,上升沿触发;
falling 表示引脚为中断输入,下降沿触发;
both 表示引脚为中断输入,边沿触发;
这个文件节点只有在引脚被配置为输入引脚的时候才存在。 当值是none时可以通过如下方法将变为中断引脚。echo “both” > edge;对于是both,falling还是rising依赖具体硬件的中断的触发方式。此方法即用户态gpio转换为中断引脚的方式。
(3)/sys/class/gpio/gpiochipN
gpiochipN 表示的就是一个gpio_chip,用来管理和控制一组gpio端口的控制器,该目录下存在一下属性文件:
base 和N相同,表示控制器管理的最小的端口编号;
lable 诊断使用的标志(并不总是唯一的);
ngpio 表示控制器管理的gpio端口数量(端口范围是:N ~ N+ngpio-1)。
1 步骤解析与代码
首先需要了解:
引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数
3516 GPIO口是分组的,一组8个口,例如GPIO9_3为 9组3口,其编号pin:9*8+3=75.
本文描述如果通过文件IO sysfs方式控制3516 GPIO端口。通过文件IO方式控制GPIO,完整的操作需要四个步骤:
- 访问/sys/class/gpio/export目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间;
- 选择GPIO接口方向(direction)输入/输出;
- 读取\写入GPIO寄存器的值;
- unexportq取消移除GPIO节点,与第一步相反。
1.1 向export文件写入GPIO编号
int GPIO_export(int pin)
{
FILE* fp;
char file_name[50];
sprintf(file_name, "/sys/class/gpio/export");
fp = fopen(file_name, "w");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "%d", pin);
fclose(fp);
return 0;
}
1.2 选择GPIO接口方向
int GPIO_direction(int pin)
{
FILE* fp;
char file_name[50];
sprintf(file_name, "/sys/class/gpio/gpio%d/direction", pin);
fp = fopen(file_name, "rb+");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "in"); //输出则为“out”
fclose(fp);
return 0;
}
1.3 读取或输入数值
int GPIO_value(int pin)
{
FILE* fp;
char file_name[50];
int value;
unsigned char buf[10];
sprintf(file_name, "/sys/class/gpio/gpio%d/value", pin);
fp = fopen(file_name, "rb+");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
memset(buf, 0, 10);
fread(buf, sizeof(char), sizeof(buf) - 1, fp);// 读取1字节数据,0/1.
//printf("%s: gpio%d_%d = %d\n", __func__,gpio_chip_num, gpio_offset_num, buf[0]-48);
value = buf[0] - 48;// 0的ASCII码为48,1的是49。这样将将字符串转化为数值
fclose(fp);
return value;
}
int GPIO_value(int pin,int gpio_out_val )
{
FILE* fp;
char file_name[50];
int value;
unsigned char buf[10];
sprintf(file_name, "/sys/class/gpio/gpio%d/value", gpio_num);
fp = fopen(file_name, "rb+");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
if (gpio_out_val)
strcpy(buf,"1");
else
strcpy(buf,"0");
fwrite(buf, sizeof(char), sizeof(buf) - 1, fp);//写入1字节数据,0/1.
//printf("%s: gpio%d_%d = %s\n", __func__,gpio_chip_num, gpio_offset_num, buf);
fclose(fp);
return 0;
}
1.4 取消GPIO节点unexport
int GPIO_unexport(int pin)
{
FILE* fp;
char file_name[50];
sprintf(file_name, "/sys/class/gpio/unexport");
fp = fopen(file_name, "w");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "%d", pin);
fclose(fp);
return 0;
}
2 全部代码
FILE* fp;
char file_name[50];
unsigned char buf[10];
int GPIO_export(int pin)
{
sprintf(file_name, "/sys/class/gpio/export");
fp = fopen(file_name, "w");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "%d", pin);
fclose(fp);
return 0;
}
/******************************************
* DIRECTION
* ***************************************/
int GPIO_direction(int pin)
{
sprintf(file_name, "/sys/class/gpio/gpio%d/direction", pin);
fp = fopen(file_name, "rb+");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "in");
fclose(fp);
return 0;
}
/******************************************
* VALUE
* ***************************************/
int GPIO_value(int pin)
{
int value;
sprintf(file_name, "/sys/class/gpio/gpio%d/value", pin);
fp = fopen(file_name, "rb+");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
memset(buf, 0, 10);
fread(buf, sizeof(char), sizeof(buf) - 1, fp);
//printf("%s: gpio%d_%d = %d\n", __func__,gpio_chip_num, gpio_offset_num, buf[0]-48);
value = buf[0] - 48;
fclose(fp);
return value;
}
int GPIO_unexport(int pin)
{
sprintf(file_name, "/sys/class/gpio/unexport");
fp = fopen(file_name, "w");
if (fp == NULL) {
printf("Cannot open %s.\n", file_name);
return -1;
}
fprintf(fp, "%d", pin);
fclose(fp);
return 0;
}
void detect_GPIO(void)
{
HI_S32 ret;
HI_U32 SDI_GPIO_control_0 = 0;//GPIO9_3
HI_U32 SDI_GPIO_control_1 = 0;//GPIO14_3
HI_U32 SDI_GPIO_control_2 = 0;//GPIO14_2
float fpga_bitrate = 0.0;
unsigned int gpio_num9_3;
unsigned int gpio_num14_3;
unsigned int gpio_num14_2;
while (1)
{
gpio_num9_3 = 9 * 8 + 3;
GPIO_export(gpio_num9_3);
GPIO_direction(gpio_num9_3);
SDI_GPIO_control_0 = GPIO_value(gpio_num9_3);
GPIO_unexport(gpio_num9_3);
/**************************************************************************************/
gpio_num14_3 = 14 * 8 + 3;
GPIO_export(gpio_num14_3);
GPIO_direction(gpio_num14_3);
SDI_GPIO_control_1 = GPIO_value(gpio_num14_3);
GPIO_unexport(gpio_num14_3);
/**************************************************************************************/
gpio_num14_2 = 14 * 8 + 2;
GPIO_export(gpio_num14_2);
GPIO_direction(gpio_num14_2);
SDI_GPIO_control_2 = GPIO_value(gpio_num14_2);
GPIO_unexport(gpio_num14_2);
// ret = HI_MPI_SYS_GetReg(0x201D0010, &SDI_GPIO_control_0);
// if (ret != 0)
// {
// printf("GPIO9_3 -- SDI_GPIO_control[0] GetReg failed\n");
// }
// ret = HI_MPI_SYS_GetReg(0x20220010, &SDI_GPIO_control_1);
// if (ret != 0)
// {
// printf("GPIO14_3 -- SDI_GPIO_control[1] GetReg failed\n");
// }
// ret = HI_MPI_SYS_GetReg(0x20220001, &SDI_GPIO_control_2);
// if (ret != 0)
// {
// printf("GPIO14_2 -- SDI_GPIO_control[2] GetReg failed\n");
// }
fpga_bitrate = (SDI_GPIO_control_2 * 4 + SDI_GPIO_control_1 * 2 + SDI_GPIO_control_0) * 0.5;
printf("++++++++++\n");
printf("SDI_GPIO_control_0 : %d\n", SDI_GPIO_control_0);
printf("SDI_GPIO_control_1 : %d\n", SDI_GPIO_control_1);
printf("SDI_GPIO_control_2 : %d\n", SDI_GPIO_control_2);
printf("fpga_bitrate : %f\n", fpga_bitrate);
printf("----------\n");
sleep(2);
}
}
int main()
{
detect_GPIO();
return 0;
}