查看: 1938|回复: 1
收起左侧

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

[复制链接]

  离线 

  • TA的每日心情
    拍拍
    2022-6-27 11:09
  • 签到天数: 25 天

    [LV.4]

    发表于 2021-5-12 15:12:28 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

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

    国外芯片技术交流-「RVBoards哪吒开发板」用 Rust 探索 RISC-V 主板 D1 之 GPIOrisc-v单片机中文社区(1)


    如下是来自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 端口
    国外芯片技术交流-「RVBoards哪吒开发板」用 Rust 探索 RISC-V 主板 D1 之 GPIOrisc-v单片机中文社区(2)

    2. DEBUGFS

    第二个利器就是 debugfs Wiki: Debugfs

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

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

    在 /sys/kernel/debug 目录下有个 gpio 文件
    1. gpiochip0: GPIOs 0-223, parent: platform/2000000.pinctrl, 2000000.pinctrl:
    2. gpio-115 (                    |usb1-vbus           ) out lo
    3. gpio-116 (                    |otg_det             ) in  lo
    4. gpio-117 (                    |otg_id              ) in  hi
    5. gpio-144 (                    |phy-rst             ) out hi
    6. gpio-166 (                    |cd                  ) in  hi IRQ
    7. gpio-202 (                    |wlan_hostwake       ) in  hi
    8. gpio-204 (                    |wlan_regon          ) out lo
    9. gpio-208 (                    |bt_wake             ) out lo
    10. gpio-209 (                    |bt_hostwake         ) in  hi
    11. gpio-210 (                    |bt_rst              ) out lo

    12. 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等)的对应关系
    1. registered pins: 88
    2. pin 32 (PB0)
    3. pin 33 (PB1)
    4. pin 34 (PB2)
    5. pin 35 (PB3)
    6. pin 36 (PB4)
    7. pin 37 (PB5)
    8. pin 38 (PB6)
    9. pin 39 (PB7)
    10. pin 40 (PB8)
    11. pin 41 (PB9)
    12. pin 42 (PB10)
    13. pin 43 (PB11)
    14. pin 44 (PB12)
    15. pin 64 (PC0)
    16. pin 65 (PC1)
    17. pin 66 (PC2)
    18. pin 67 (PC3)
    19. ...
    复制代码

    3. SYSFS

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

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

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

    export 和 unexport 用来控制 gpio 的开启与关闭
    1. # 启用 2020 号 gpio 端口, 根据上面的信息,可以知道 2020 对应扩展 IO PP0 , 也就是 40pin 引脚中的 GPIO8
    2. echo 2020 > export

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

    4. cd /sys/class/gpio/gpio2020
    5. # 设置为输出
    6. echo out > direction
    7. # 设置高电平
    8. echo 1 > value
    9. # 设置低电平
    10. echo 0 > value

    11. # 执行代码后, 如果接了 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
    1. extern crate gpio_cdev;

    2. use gpio_cdev::*;

    3. fn main() {
    4.     let  chip_iterator = match chips() {
    5.         Ok(chips) => chips,
    6.         Err(e) => {
    7.             println!("Failed to get chip iterator: {:?}", e);
    8.             return;
    9.         }
    10.     };

    11.     for chip in chip_iterator {
    12.         let chip = match chip {
    13.             Ok(chip) => chip,
    14.             Err(err) =>  panic!("Failed to open the chip: {:?}", err)
    15.         };
    16.             println!(
    17.                 "GPIO chip: {}, "{}", "{}", {} GPIO Lines",
    18.                 chip.path().to_string_lossy(),
    19.                 chip.name(),
    20.                 chip.label(),
    21.                 chip.num_lines()
    22.             );
    23.             for line in chip.lines() {
    24.                 match line.info() {
    25.                     Ok(info) => {
    26.                         let mut flags = vec![];

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

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

    33.                         if info.is_active_low() {
    34.                             flags.push("active-low");
    35.                         }
    36.                         if info.is_open_drain() {
    37.                             flags.push("open-drain");
    38.                         }
    39.                         if info.is_open_source() {
    40.                             flags.push("open-source");
    41.                         }

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

    47.                         println!(
    48.                             "\tline {lineno:>3}: {name} {consumer} {usage}",
    49.                             lineno = info.line().offset(),
    50.                             name = info.name().unwrap_or("unused"),
    51.                             consumer = info.consumer().unwrap_or("unused"),
    52.                             usage = usage,
    53.                         );
    54.                     }
    55.                     Err(e) => println!("\tError getting line info: {:?}", e),
    56.                 }
    57.             }
    58.             println!();
    59.     }
    60. }
    复制代码

    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-V芯片
    下一篇:什么是RVBoards? 什么是Perf-V?
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

      离线 

  • TA的每日心情
    开心
    2023-1-20 22:24
  • 签到天数: 54 天

    [LV.5]

    发表于 2023-3-2 09:36:37 | 显示全部楼层
    这个不错
    有事请在RISC-V单片机中文社区内留言,或请发邮件至admin@risc-v1.com,我们会统一尽快回复。
    【本人基本每天不定时在线,欢迎加好友,欢迎发信息,欢迎互相骚扰!!!】
    点评回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-26 22:11 , Processed in 0.530664 second(s), 51 queries .

    快速回复 返回顶部 返回列表