Blog Of Leung

personal blog & work notes

View project onGitHub
 

在pcba-test模式中控制gpio

在工厂测试固件中,基本的操作其实就是在用户空间操作底层设备文件,从而控制特定的硬件,从而判断平板上的器件是否能工作,这样就能在贴片之后,组装之前,简单地检测出虚焊,不良物料引起的问题。

假如现在需要控制的不是某个模块,而仅仅是某个gpio口,那就要做点别的事情了。

内核中,并不存在直接操作某个gpio口的设备文件,实际上也不可能存在,因为gpio口太多了。但是,内核中有一个通用的gpio操作接口,路径在"/sys/class/gpio"。内核中一般直接支持,如果没有这个目录,那就在编译内核的时候选上CONFIG_GPIO_SYSFS即可。

gpio目录说明

  • /sys/class/gpio/export,往该文件中写入gpio口的编号,内核就会导出需要控制的gpio口
  • /sys/class/gpio/unexport,与export作用相反,取消导出
  • /sys/class/gpio/gpiochipxxx,这些目录有多少个表明系统中存在的gpio有多少组gpio,起始编号等等
  • /sys/class/gpio/gpioxxx,这种目录(注意区分上面的gpiochipxxx)是通知内核导出之后才会产生的,里面有控制某个被导出的gpio的接口
  • /sys/class/gpio/gpioxxx/direction,往该文件中写入特定参数,就可以控制gpio的状态,可接受的参数有in,out,high,low,其中high/low会直接设置为out,并将gpio的value设为1/0

关于编号的计算

计算引脚编号并不复杂,举个例子,假设现在有四组gpio,分别是GPIO0到GPIO3,在/sys/class/gpio目录下,我们已经看到四个目录,分别是gpiochip160,gpiochip192,gpiochip224,gpiochip256。

从这里我们可以得到几个信息,四组gpio对应的起始编号可以知道,分别是160,191,224,256;每组gpio的数量可以知道,不超过32个;所以最小的gpio编号就是160,最大的编号应该256+32=288。

假设我需要控制的gpio口是RK30_PIN3_PD4,那么就应该是属于GPIO3,属于第四组,那么显然起始编号是256。然后查看各个平台的gpio定义,如kernel/arch/arm/mach-rk30/include/mach/gpio.h,里面会有gpio的编号定义,截取一些片段:

#define RK30_PIN3_PC7       (3*NUM_GROUP + PIN_BASE + 23)
#define RK30_PIN3_PD0       (3*NUM_GROUP + PIN_BASE + 24)
#define RK30_PIN3_PD1       (3*NUM_GROUP + PIN_BASE + 25)
#define RK30_PIN3_PD2       (3*NUM_GROUP + PIN_BASE + 26)
#define RK30_PIN3_PD3       (3*NUM_GROUP + PIN_BASE + 27)
#define RK30_PIN3_PD4       (3*NUM_GROUP + PIN_BASE + 28)

这里需要关心的,只是某个gpio口相对于起始编号的偏移即可,还是上面说到的RK30_PIN3_PD4,NUM_GROUP=32,PIN_BASE=160,实际上3*NUM_GROUP+PIN_BASE=256,就是上面看到的四个起始编号的最后一个,然后偏移是28,所以RK30_PIN3_PD4的gpio编号等于256+28=284

必要的东西已经准备好

接下来,就可以写个简单的程序控制gpio了,

#define LOG_TAG "Moto"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/ioctl.h>
#include <pthread.h>
#include "language.h"
#include "test_case.h"
#include "moto_test.h"

#define MOTO_GPIO_NUM        "284"
#define SYS_GPIO_PATH    "/sys/class/gpio/export"
#define MOTO_GPIO_PATH    "/sys/class/gpio/gpio284/direction"
#define HIGH_VALUE        "high"
#define LOW_VALUE         "low"

void* moto_test(void *argv)
{
    int ret;
    int result;
    int fd, fdd;
    int value;
    char buffer[3];
    struct testcase_info *tc_info = (struct testcase_info*)argv;
    ui_print_xy_rgba(0,get_cur_print_y(),0,255,0,255,"%s:[%s]\n",PCBA_MOTO,"自动模式");

    if(tc_info->y <= 0)
        tc_info->y  = get_cur_print_y();

    fdd = open(SYS_GPIO_PATH, O_WRONLY);
    if (fdd < 0)
        printf("open %s failed\n", SYS_GPIO_PATH);
    else
    ret = write(fdd, MOTO_GPIO_NUM, sizeof(MOTO_GPIO_NUM));

    for(;;)
    {
        fd = open(MOTO_GPIO_PATH, O_RDWR);
        if (fd < 0){
            printf("open %s failed\n", MOTO_GPIO_PATH);
            ui_print_xy_rgba(0,tc_info->y,255,0,0,255,"%s:[%s]\n",PCBA_MOTO,"启动失败");
            tc_info->result = -1;
            return argv;
        }

        value = write(fd, HIGH_VALUE, sizeof(HIGH_VALUE));
        sleep(2);
        value = write(fd, LOW_VALUE, sizeof(LOW_VALUE));
        sleep(2);
        close(fd);
    }
    return argv;
}

上面是基于rk的pcba test框架写的一个gpio控制,就是按照上面说的,首先往export文件中写入一个gpio编号,等内核导出该gpio口之后,直接往相应的direction文件写入high或者low参数,即可实现控制。这里具体是控制一个外接的马达,让它每隔2秒震动一次。

详细:github.rk-pcba-test-addition

Author:leung

21 Jul 2014

← Home

comments powered by Disqus