TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结

#PS:要转载请注明出处,本人版权所有

#PS:这个只是 《 我自己 》理解,如果和你的

#原则相冲突,请谅解,勿喷

起因

我们有个项目,做了一个基于TX2核心板的硬件板卡,这个板卡除了做相关算法的检测之外,还得提供一些控制LED啊、通过拨码开关这些来设置一些内容的小功能,你说气不气,这些小功能还必须要实现。如果LED和拨码开关直接挂载到tx2的gpio上的话,就没有必要写本文了,没意义,因为只要学过嵌入式的人,给他一个板子,再差劲,读取和设置一个gpio的高低电平总会吧。如果不会,建议还多学学嵌入式基础知识(从单片机玩起来,先裸奔,再上OS)。

这里我们知道,其实对于芯片来说,引脚是非常珍贵的,如果芯片所需要实现的功能复杂,那么通用的io管脚异常珍贵,这里就出现了一个种器件,叫做IO扩展器(所实话,我都不知道这样翻译对不对),从名字可知,就是较少的引脚扩展出更多的引脚,本文就是用两个引脚扩展出了16个引脚。

TX2上,由于使用了Linux,读取和设置gpio也是非常简单的,直接打开相关的gpio设备,读写即可。不要问我为啥要用linux,不用其他os,或者直接裸机控制,我只能够回答曰:我是想啊,可是我实力不允许啊,什么caffe、opencv、ncnn、cuda等等堆到其他系统或者裸机下,我着实能力不够,弄不过去,关键还麻烦。

IO扩展器

IO扩展器原理简介

其实本文的核心就是IO扩展器,这个器件由于我玩的板子少,见识少,我是第一次见到这种器件。下图就是这种器件在tx2手册里面的推荐使用方法。
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第1张图片
这种器件就是通过某种总线,然后扩展出尽可能多的io口。这里的这个器件通过I2C总线,扩展出16个io口。
这里我们可以看到:
SCL和SDA是I2C通信总线,A0和A1是可编程配置I2C从器件地址。(这里不懂也没关系,就是这个器件的地址可以编程设置,至于为啥要有这个地址,可以简单理解为一个总线挂载多个设备,某一时刻总线只能为其中一个设备提供服务,这些设备的区分就是通过地址来完成的。)

P00-P17是扩展出来的IO口。

知道以上足够了,没学过的也足够了。

这个器件的特性是:
通过I2C协议操作他的寄存器,他有8个8位寄存器,0-1寄存器是INPUT用,2-3寄存器是OUTPUT用,4-5好像是优先级裁决,6-7是配置寄存器,就是配置IO口是输出还是输入,如果接触过单片机、stm32这种的GPIO程序的话,是很好理解的。(手动滑稽,我出了校门就没接触过了)
不要问下图的是什么器件(问就是不知道,手动滑稽),这只是举个例子,这个io扩展器的寄存器分配以及功能就是这样的。
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第2张图片
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第3张图片

IO扩展器编程操作—shell command

首先这个器件是通过I2C协议操作的,不用关心I2C是什么,他们你可以类比为HTTP。
那么Linux上怎么通过I2C操作这个器件呢?
首先,Linux上有一组工具:i2c-tool,它可以读取所有芯片的i2c bus上挂载的芯片,设置和读取寄存器等等,拿来做测试或者封装一个程序都是不错的。TX2的ubuntu16.04是自带这个工具的,他的详细用法大家去百度,我不造轮子了。
在Ubuntu里面操作I2C是非常简单的,你不需要关心I2C的具体传输规定,不用管时序这些烦人的事情。
首先我们先用工具来测试,美滋滋:
还记得上文我提了这个IO扩展器的从地址的事情吗?由于我的A0和A1都是接的低电平,在这里我的器件地址是0x74,怎么来的,看下图。
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第4张图片
然后通过i2cdetect查看我们器件的位置(0x74)(注意,这个命令需要传入一个I2C总线序号,我这里是0,也就是说你要知道你这个IO扩展器挂载到哪个总线上的,这和SCL和SDL接线有关,有兴趣的可以去翻一翻手册就知道了,UU代表有人在占用这个设备)

shell:>i2cdetect -y -r -a 0

TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第5张图片
i2cdump可以通过标准i2c协议探测出所有的寄存器的值,下图8个寄存器的值就的出来了,分别对应上面的寄存器说明。XX代表没有这个寄存器。
shell:>i2cdump -f -y 0 0x74
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第6张图片
然后:
i2cset -f -y i2c_bus_num slave_addr reg_num value 设置寄存器值
i2cget -f -y i2c_bus_num slave_addr reg_num 获取寄存器值

其实通过上面的操作就可以完成整个io扩展器的操作,我们可以通过程序执行shell命令的方式设置和操作值。

IO扩展器编程操作—syscall

实际上,linux做了很多东西,我们可以用标准的linux sys-api来完成以上内容,其实这些api就是i2ctool使用的部分。
下面不墨迹,直接给出led操作的接口,有需要的参考吧。

int open_led_device(const char * i2c_bus_num, int slave_addr){

    int fd = 0; 

    if ( 0 > (fd = open(i2c_bus_num, O_RDWR)) ){//打开i2c总线

        perror("open i2c bus error:");
        return -1;
    }

    if(ioctl(fd, I2C_SLAVE_FORCE, DEVICE_I2C_ADDR) < 0) {//设置从器件地址,这里使用I2C_SLAVE_FORCE进行强行设置,那么这个设备忙

        perror("set device slave addr error:"); 
        return -1; 
    }

    if ( 0 > write_led_register(fd, LED_REG1_CFG_ADDR, LED_REG1_CFG_VAL) ){//设置写寄存器值,这两个宏和你的硬件连线有关。这里不给出。

        printf("init pin for output-mode failed.\n");
        close(fd);
        return -1;
    }

    return fd;

}

int read_led_register(int fd, char reg_addr, char *read_val){//读寄存器

    if (write(fd, &reg_addr, 1) != 1){//write reg addr ,从器件地址通过open接口设置好后,先写入要读的reg地址

        perror("set reg addr error:"); 
        return -1; 
    }

    if ( read(fd, read_val, 1) != 1 ){//read data,等待i2c返回刚刚要查询的reg值

        perror("read reg error:"); 
        return -1; 
    }
    return 0;
}

int write_led_register(int fd, char reg_addr, char data){//写寄存器

    char tmp_buf[2];


    tmp_buf[0] =  reg_addr;//reg 地址
    tmp_buf[1] = data;//reg 值


    if (write(fd, tmp_buf, 2) != 2){//write data

        perror("write data error:"); 
        return -1; 
    }

    return 0;
}

void close_led_device(int fd){//关闭

    close(fd);
}

LED灯

此处省略XXX字。
相信每个人都知道,常规情况下,在LED灯的两边加电源正极和负极,灯就能亮。在电路设计上,一般来说,LED灯的一端都是和电源正极或者负极是连接好的,另一端和GPIO口接上。如果GPIO输出的电压和另一端电压逻辑一致(比如都是高电平、都是低电平),灯就不亮,反之就亮。
注意:这段话是有毛病的,但是一般人这样理解就行了(不了解电子电路的就看到这就行了)。对于懂的人,这里多说一句,这里还有一个三极管做开关作用,也是就说LED灯两端都接在电源正负极,中间有个三极管开关。

拨码开关

这种器件,又是另外一种新奇的东西了,感觉我这两年写的“祖传屎山“太多了,现在看到各种硬件器件都是眼前一亮的感觉。
就是类似下图这种。
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第7张图片
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第8张图片
其作用是:
你可以人为的按这个±号按钮,设置数字,这个数字会反应到电路上,从而芯片可以读取你设置的数字。
说白了,你的系统中有个数字参数,你可以通过这种器件进行手动设置,通过驱动程序,就可以更改这个系统参数,是不是 so 简单。

这里简单说明一下电路是怎么反应出对应的数字的:
我就举个栗子,下图是个例子拨码开关(手动滑稽,这里多说一句,上图的拨码开关,是4个拨码开关合在一起的,下图的这个输出编码是一个拨码开关的)
TX2 核心板 GPIO、IO扩展器、拨码开关、LED灯 使用总结_第9张图片
这里可以简单理解为:
一个拨码开关有5个引脚,一个引脚是C,接GND或者VCC,其他4个是编码引脚,是需要接GPIO,并去取编码的。
其实很简单:
例如:C端我接VCC,1248默认值为0,那么数字1,1号引脚接通,那么8421io口输出二进制就是0001,转换为10进制,就是1.
然后写个程序读取这4个脚的值,转换一下,就OK。
#PS:请尊重原创,不喜勿喷

#PS:要转载请注明出处,本人版权所有.

有问题请留言,看到后我会第一时间回复

你可能感兴趣的:(嵌入式,常识,linux开发)