sky 发表于 2021-5-12 15:12:28

「RVBoards哪吒开发板」用 Rust 探索 RISC-V 主板 D1 之 GPIO

本帖最后由 sky 于 2021-5-12 15:12 编辑



如下是来自RVBoards开源小组liangdi关于「哪吒开发板」的技术文章。


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

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

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

辅助利器

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

1. 原理图

已经开放原理图下载, 下载地址: https://www.rvboards.org/forum/c ... es/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 文件
gpiochip0: GPIOs 0-223, parent: platform/2000000.pinctrl, 2000000.pinctrl:
gpio-115 (                  |usb1-vbus         ) out lo
gpio-116 (                  |otg_det             ) inlo
gpio-117 (                  |otg_id            ) inhi
gpio-144 (                  |phy-rst             ) out hi
gpio-166 (                  |cd                  ) inhi IRQ
gpio-202 (                  |wlan_hostwake       ) inhi
gpio-204 (                  |wlan_regon          ) out lo
gpio-208 (                  |bt_wake             ) out lo
gpio-209 (                  |bt_hostwake         ) inhi
gpio-210 (                  |bt_rst            ) out lo

gpiochip1: GPIOs 2020-2027, parent: i2c/2-0038, pcf8574, can sleep:里面内容显示了,板子上有两部分 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等)的对应关系
registered pins: 88
pin 32 (PB0)
pin 33 (PB1)
pin 34 (PB2)
pin 35 (PB3)
pin 36 (PB4)
pin 37 (PB5)
pin 38 (PB6)
pin 39 (PB7)
pin 40 (PB8)
pin 41 (PB9)
pin 42 (PB10)
pin 43 (PB11)
pin 44 (PB12)
pin 64 (PC0)
pin 65 (PC1)
pin 66 (PC2)
pin 67 (PC3)
...
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() {
    letchip_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 等方面的操作,欢迎关注,欢迎拍砖。


RISC-VMCU 发表于 2023-3-2 09:36:37

这个不错
页: [1]
查看完整版本: 「RVBoards哪吒开发板」用 Rust 探索 RISC-V 主板 D1 之 GPIO