用Rust探索RISC-V主板D1之GPIO

///

作者:山人几言
链接:https://www.zhihu.com/question/19704852/answer/19760467
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

如果是在已经适配好的linux内核上,那么相信已经有了完成的gpiochip,可以在用户空间/sys/class/gpio目录下看到,如:

export

gpiochip0/

gpiochip32/

gpiochip64/

gpiochip96/

unexport

然后对照手册看下需要用到哪个GPIO,举个例子:

如果使想用GPIO1_20

那么GPIO Number就是 1 x 32 + 20 = 54

使用分两种情况:

1. 用户空间:

echo 54 > export

这样在这个/sys/class/gpio目录下就会产生gpio54文件夹

在文件夹下需要用到的有两个文件:

direction 用来配置输入(in)还是输出(out)

value 如果这个GPIO配置成了输入,那么通过cat value可以查看当前这个GPIO是什么电位;如果配置成了输出,那么可以通过echo 1/0 > value给这个GPIO口指定输出电平。

2. 内核空间(驱动):

#include <linux/gpio.h>

gpio_request_one(54, GPIOF_INIT_HIGH, "gpio1_20")

这里是配置成输出,默认高电平,别名(label)为gpio1_20——就是给你的IO口取个名字。

gpio_request_one(54, GPIOF_IN, "gpio1_20")

这个就是配置成输入。

使用完后别忘了free

gpio_free(54);

具体GPIO接口详见:

Linux/Documentation/gpio.txt

希望能够帮到你。

//

用 Rust 探索RISC-V 主板 
全志D1芯片之GPIO 

「哪吒开发板」用Rust探索RISC-V主板D1之GPIO-嵌入式系统-与非网

gpio 是单片机或者单板机和外部硬件沟通的桥梁,通过它可以控制外部硬件,可以建立通讯,可以获取传感器数据等

D1 开发板和树莓派一样,对外引出了 40pin 引脚, 这些引脚包含3.3v,5v供电, GND , 以及几个未使用(NC)引脚, 然后就是我们要讲到的 GPIO 引脚.


辅助利器

开发 gpio 应用离不开几个利器

1. 原理图

已经开放原理图下载,

下载地址: https://www.rvboards.org/forum/cn/assets/uploads/files/1620265818082-d1哪吒开发板原理图20210224.pdf


根据原理图,我们可以看到 40pin 引脚与之对应的芯片端口

这里要说明 D1 板子用 PCF8574 扩展了 8 个 IO 分别是 PP0-PP7 ,其他引出的 IO 来至 D1 这颗芯片, 并且由于 IO 端口不足, 40 Pin 里面物理 32pin 和 38pin 为未启用(NC), 树莓派中是两个 GPIO 端口

2. DEBUGFS

第二个利器就是 debugfs Wiki: Debugfs

debugfs 传承了 Linux 一切皆文件的理念,把内核更多信息通过文件系统展现给开发者,这里当然就包括了我们要的 gpio 信息

debugfs 默认挂载在 /sys/kernel/debug , 如果没有挂载,可以执行 mount -t debugfs none /sys/kernel/debug 挂载

在 /sys/kernel/debug 目录下有个 gpio 文件

里面内容显示了,板子上有两部分 gpio 组成,第一部分(gpiochip0)有 0-223 ,共224 个 gpio 端口,来自 D1 芯片, 第二部分(gpiochip1) 2020-2027 , 共8个 gpio 端口来自 PCF8574, 并且 8574 是通过 i2c 连接的 , 同时又显示了gpiochip0 中已经做了配置的 GPIO 接口

D1 芯片中的 gpio 信息可以在 /sys/kernel/debug/pinctrl/2000000.pinctrl/pins 找到编号和芯片引脚名称(PA1,PB2等)的对应关系

3. SYSFS

sysfs 和 debugfs 一样,通过文件系统,用户不仅可以查看信息,还可以操作硬件.

 /sys/class/gpio 目录下有四个文件,分别是 export,gpiochip0 ,gpiochip2020,unexport

其中 gpiochip0,gpiochip2020 链接的是芯片两个gpio主控

export 和 unexport 用来控制 gpio 的开启与关闭

# 启用 2020 号 gpio 端口, 根据上面的信息,可以知道 2020 对应扩展 IO PP0 , 也就是 40pin 引脚中的 GPIO8
echo 2020 > export 

# 执行完 echo 2020 > export  后, 会在 /sys/class/gpio 中创建一个目录 /sys/class/gpio/gpio202 , 在这个目录里面就可以设置 gpio 的in 和 out 以及读取或者输出高低电平

cd /sys/class/gpio/gpio2020
# 设置为输出
echo out > direction 
# 设置高电平
echo 1 > value
# 设置低电平
echo 0 > value

# 执行代码后, 如果接了 LED 灯, 灯就会亮了又灭了

Rust 在 gpio 方面的支持情况

rust 有以下一些 crate

1.  LINUX-EMBEDDED-HAL
Implementation of the embedded-hal traits for Linux devices

2. GPIO-CDEV
基于 GPIO character device ABI 的库

3. SYSFS-GPIO
基于 sysfs 操作 gpio 的库, 原理如上面手动操作 sysfs 是一样的

4. GPIO-UTILS
操作 gpio 的小工具程序, 基于 sysfs_gpio

Rust Demo (使用cdev-gpio)

list gpios

extern crate gpio_cdev;

use gpio_cdev::*;

fn main() {
    let  chip_iterator = match chips() {
        Ok(chips) => chips,
        Err(e) => {
            println!("Failed to get chip iterator: {:?}", e);
            return;
        }
    };

    for chip in chip_iterator {
        let chip = match chip {
            Ok(chip) => chip,
            Err(err) =>  panic!("Failed to open the chip: {:?}", err)
        };
            println!(
                "GPIO chip: {}, \"{}\", \"{}\", {} GPIO Lines",
                chip.path().to_string_lossy(),
                chip.name(),
                chip.label(),
                chip.num_lines()
            );
            for line in chip.lines() {
                match line.info() {
                    Ok(info) => {
                        let mut flags = vec![];

                        if info.is_kernel() {
                            flags.push("kernel");
                        }

                        if info.direction() == LineDirection::Out {
                            flags.push("output");
                        }

                        if info.is_active_low() {
                            flags.push("active-low");
                        }
                        if info.is_open_drain() {
                            flags.push("open-drain");
                        }
                        if info.is_open_source() {
                            flags.push("open-source");
                        }

                        let usage = if !flags.is_empty() {
                            format!("[{}]", flags.join(" "))
                        } else {
                            "".to_owned()
                        };

                        println!(
                            "\tline {lineno:>3}: {name} {consumer} {usage}",
                            lineno = info.line().offset(),
                            name = info.name().unwrap_or("unused"),
                            consumer = info.consumer().unwrap_or("unused"),
                            usage = usage,
                        );
                    }
                    Err(e) => println!("\tError getting line info: {:?}", e),
                }
            }
            println!();
    }
}

cdev-gpio 的接口中, 通过 chips() 获取 gpio控制器列表, D1 中的/dev/gpiochip0 和 /dev/gpiochip1

每个 chip 中有 lines 列表,就是控制器下的 gpio 列表 line 就是 gpio 对象, 可以 进行 set_value , get_value ,以及设定输入输出等操作

总体来说, Linux 对 gpio 封装已经很简单, rust 在这方面支持也比较完善. 后续文章还有 i2c, spi , uart 等方面的操作,欢迎关注,欢迎拍砖.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值