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)
image.png

(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,完整的操作需要四个步骤:

  1. 访问/sys/class/gpio/export目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间;
  2. 选择GPIO接口方向(direction)输入/输出;
  3. 读取\写入GPIO寄存器的值;
  4. unexportq取消移除GPIO节点,与第一步相反。

1.1 向export文件写入GPIO编号

  1. int GPIO_export(int pin)
  2. {
  3. FILE* fp;
  4. char file_name[50];
  5. sprintf(file_name, "/sys/class/gpio/export");
  6. fp = fopen(file_name, "w");
  7. if (fp == NULL) {
  8. printf("Cannot open %s.\n", file_name);
  9. return -1;
  10. }
  11. fprintf(fp, "%d", pin);
  12. fclose(fp);
  13. return 0;
  14. }

1.2 选择GPIO接口方向

  1. int GPIO_direction(int pin)
  2. {
  3. FILE* fp;
  4. char file_name[50];
  5. sprintf(file_name, "/sys/class/gpio/gpio%d/direction", pin);
  6. fp = fopen(file_name, "rb+");
  7. if (fp == NULL) {
  8. printf("Cannot open %s.\n", file_name);
  9. return -1;
  10. }
  11. fprintf(fp, "in"); //输出则为“out”
  12. fclose(fp);
  13. return 0;
  14. }

1.3 读取或输入数值

  1. int GPIO_value(int pin)
  2. {
  3. FILE* fp;
  4. char file_name[50];
  5. int value;
  6. unsigned char buf[10];
  7. sprintf(file_name, "/sys/class/gpio/gpio%d/value", pin);
  8. fp = fopen(file_name, "rb+");
  9. if (fp == NULL) {
  10. printf("Cannot open %s.\n", file_name);
  11. return -1;
  12. }
  13. memset(buf, 0, 10);
  14. fread(buf, sizeof(char), sizeof(buf) - 1, fp);// 读取1字节数据,0/1.
  15. //printf("%s: gpio%d_%d = %d\n", __func__,gpio_chip_num, gpio_offset_num, buf[0]-48);
  16. value = buf[0] - 48;// 0的ASCII码为48,1的是49。这样将将字符串转化为数值
  17. fclose(fp);
  18. return value;
  19. }
  1. int GPIO_value(int pin,int gpio_out_val )
  2. {
  3. FILE* fp;
  4. char file_name[50];
  5. int value;
  6. unsigned char buf[10];
  7. sprintf(file_name, "/sys/class/gpio/gpio%d/value", gpio_num);
  8. fp = fopen(file_name, "rb+");
  9. if (fp == NULL) {
  10. printf("Cannot open %s.\n", file_name);
  11. return -1;
  12. }
  13. if (gpio_out_val)
  14. strcpy(buf,"1");
  15. else
  16. strcpy(buf,"0");
  17. fwrite(buf, sizeof(char), sizeof(buf) - 1, fp);//写入1字节数据,0/1.
  18. //printf("%s: gpio%d_%d = %s\n", __func__,gpio_chip_num, gpio_offset_num, buf);
  19. fclose(fp);
  20. return 0;
  21. }

1.4 取消GPIO节点unexport

  1. int GPIO_unexport(int pin)
  2. {
  3. FILE* fp;
  4. char file_name[50];
  5. sprintf(file_name, "/sys/class/gpio/unexport");
  6. fp = fopen(file_name, "w");
  7. if (fp == NULL) {
  8. printf("Cannot open %s.\n", file_name);
  9. return -1;
  10. }
  11. fprintf(fp, "%d", pin);
  12. fclose(fp);
  13. return 0;
  14. }

2 全部代码

  1. FILE* fp;
  2. char file_name[50];
  3. unsigned char buf[10];
  4. int GPIO_export(int pin)
  5. {
  6. sprintf(file_name, "/sys/class/gpio/export");
  7. fp = fopen(file_name, "w");
  8. if (fp == NULL) {
  9. printf("Cannot open %s.\n", file_name);
  10. return -1;
  11. }
  12. fprintf(fp, "%d", pin);
  13. fclose(fp);
  14. return 0;
  15. }
  16. /******************************************
  17. * DIRECTION
  18. * ***************************************/
  19. int GPIO_direction(int pin)
  20. {
  21. sprintf(file_name, "/sys/class/gpio/gpio%d/direction", pin);
  22. fp = fopen(file_name, "rb+");
  23. if (fp == NULL) {
  24. printf("Cannot open %s.\n", file_name);
  25. return -1;
  26. }
  27. fprintf(fp, "in");
  28. fclose(fp);
  29. return 0;
  30. }
  31. /******************************************
  32. * VALUE
  33. * ***************************************/
  34. int GPIO_value(int pin)
  35. {
  36. int value;
  37. sprintf(file_name, "/sys/class/gpio/gpio%d/value", pin);
  38. fp = fopen(file_name, "rb+");
  39. if (fp == NULL) {
  40. printf("Cannot open %s.\n", file_name);
  41. return -1;
  42. }
  43. memset(buf, 0, 10);
  44. fread(buf, sizeof(char), sizeof(buf) - 1, fp);
  45. //printf("%s: gpio%d_%d = %d\n", __func__,gpio_chip_num, gpio_offset_num, buf[0]-48);
  46. value = buf[0] - 48;
  47. fclose(fp);
  48. return value;
  49. }
  50. int GPIO_unexport(int pin)
  51. {
  52. sprintf(file_name, "/sys/class/gpio/unexport");
  53. fp = fopen(file_name, "w");
  54. if (fp == NULL) {
  55. printf("Cannot open %s.\n", file_name);
  56. return -1;
  57. }
  58. fprintf(fp, "%d", pin);
  59. fclose(fp);
  60. return 0;
  61. }
  62. void detect_GPIO(void)
  63. {
  64. HI_S32 ret;
  65. HI_U32 SDI_GPIO_control_0 = 0;//GPIO9_3
  66. HI_U32 SDI_GPIO_control_1 = 0;//GPIO14_3
  67. HI_U32 SDI_GPIO_control_2 = 0;//GPIO14_2
  68. float fpga_bitrate = 0.0;
  69. unsigned int gpio_num9_3;
  70. unsigned int gpio_num14_3;
  71. unsigned int gpio_num14_2;
  72. while (1)
  73. {
  74. gpio_num9_3 = 9 * 8 + 3;
  75. GPIO_export(gpio_num9_3);
  76. GPIO_direction(gpio_num9_3);
  77. SDI_GPIO_control_0 = GPIO_value(gpio_num9_3);
  78. GPIO_unexport(gpio_num9_3);
  79. /**************************************************************************************/
  80. gpio_num14_3 = 14 * 8 + 3;
  81. GPIO_export(gpio_num14_3);
  82. GPIO_direction(gpio_num14_3);
  83. SDI_GPIO_control_1 = GPIO_value(gpio_num14_3);
  84. GPIO_unexport(gpio_num14_3);
  85. /**************************************************************************************/
  86. gpio_num14_2 = 14 * 8 + 2;
  87. GPIO_export(gpio_num14_2);
  88. GPIO_direction(gpio_num14_2);
  89. SDI_GPIO_control_2 = GPIO_value(gpio_num14_2);
  90. GPIO_unexport(gpio_num14_2);
  91. // ret = HI_MPI_SYS_GetReg(0x201D0010, &SDI_GPIO_control_0);
  92. // if (ret != 0)
  93. // {
  94. // printf("GPIO9_3 -- SDI_GPIO_control[0] GetReg failed\n");
  95. // }
  96. // ret = HI_MPI_SYS_GetReg(0x20220010, &SDI_GPIO_control_1);
  97. // if (ret != 0)
  98. // {
  99. // printf("GPIO14_3 -- SDI_GPIO_control[1] GetReg failed\n");
  100. // }
  101. // ret = HI_MPI_SYS_GetReg(0x20220001, &SDI_GPIO_control_2);
  102. // if (ret != 0)
  103. // {
  104. // printf("GPIO14_2 -- SDI_GPIO_control[2] GetReg failed\n");
  105. // }
  106. fpga_bitrate = (SDI_GPIO_control_2 * 4 + SDI_GPIO_control_1 * 2 + SDI_GPIO_control_0) * 0.5;
  107. printf("++++++++++\n");
  108. printf("SDI_GPIO_control_0 : %d\n", SDI_GPIO_control_0);
  109. printf("SDI_GPIO_control_1 : %d\n", SDI_GPIO_control_1);
  110. printf("SDI_GPIO_control_2 : %d\n", SDI_GPIO_control_2);
  111. printf("fpga_bitrate : %f\n", fpga_bitrate);
  112. printf("----------\n");
  113. sleep(2);
  114. }
  115. }
  116. int main()
  117. {
  118. detect_GPIO();
  119. return 0;
  120. }