如下是来自rvboards开源小组liangdi关于「哪吒开发板」的技术文章。
用 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 引脚中的 gpio8echo 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!( line {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!( error 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 在这方面支持也比较完善。
什么是混合电路?
以色列击落俄罗斯无人机,尴尬发现是以色列出产
Kasite微孔加工设备|挑战超高精密加工技术难点
众多知名厂商集体亮相亮相NEPCON South China 2016展会现场
物联网与大数据将改变未来我们与城市互动的方式
「哪吒开发板」用Rust 探索RISC-V主板D1之GPIO
Si-Ware联手汉高首推内置光谱传感器产品
SKYLAB:蓝牙/UWB室内定位应用分析
基于Cortex M33的LPC5500系列MCU主要功能特性介绍
科技企业IHS智触产品将在南方医科大学深圳医院落地商用
离线型反激式转换器原理图讲解
启明云端分享 | 一文带你看懂乐鑫ESP32-C2/C3及ESP8266的区别
温度控制仪表的发展历程
Molex 和Samtec携手提供新一代数据中心解决方案
真的没有司机,深圳可以这样打车
远程I/O与现场总线,我们到底该选择谁
软体机器人为什么如此吸引人
苹果新iPad Pro将升级成OLED屏幕?
固定式涡轮全焊接球阀介绍
地质灾害监测方案(地质灾害监测原理与方法)