wiringx
简介
wiringX
是一个开源的 GPIO 控制库,旨在为不同的嵌入式平台提供通用且统一的 GPIO 控制接口。它基于 WiringPi 库进行了改进和扩展,并支持多种嵌入式平台,对Milk-V Duo
也进行了适配。使用wiringX
,开发者可以使用相同的代码来控制不同平台上的 GPIO 引脚,简化了跨平台开发的工作,使得开发嵌入式应用程序更加方便和灵活。
本文将分为如下4个部分介绍如何使用 wiringX 在 Duo 上开发应用:
- 基于 wiringX 的应用程序编译环境配置
- 基本使用方法代码示范
- 一些使用 wiringX 实现的 Demo 和项目介绍
- wiringX 的 AP
如果您对 wiringX 的使用方法已经非常熟悉,可以直接参考示例代码仓库: duo-examples。
注意,Duo 系列的很多引脚功能是复用的,在使用wiringX
来控制 Duo/Duo256M/DuoS 各引脚的功能时,要先确认一下引脚当前的状态是不是自己需要的功能, 如果不是,可以用duo-pinmux
命令来切换为所需功能。
具体方法请参考: 引脚复用。
Duo 系列开发板 wiringX 引脚序号
Duo/Duo256M
Duo 和 Duo256M 的 wiringX 引脚序号, 与引脚名序号是一致的,蓝色 LED 控制引脚不在引出的 40PIN 物理引脚上,其 wiringX 的序号是25
。
wiringX | PIN NAME | PIN# | PIN# | PIN NAME | wiringX |
---|---|---|---|---|---|
0 | GP0 | 1 | 40 | VBUS | |
1 | GP1 | 2 | 39 | VSYS | |
GND | 3 | 38 | GND | ||
2 | GP2 | 4 | 37 | 3V3_EN | |
3 | GP3 | 5 | 36 | 3V3(OUT) | |
4 | GP4 | 6 | 35 | ||
5 | GP5 | 7 | 34 | ||
GND | 8 | 33 | GND | ||
6 | GP6 | 9 | 32 | GP27 | 27 |
7 | GP7 | 10 | 31 | GP26 | 26 |
8 | GP8 | 11 | 30 | RUN | |
9 | GP9 | 12 | 29 | GP22 | 22 |
GND | 13 | 28 | GND | ||
10 | GP10 | 14 | 27 | GP21 | 21 |
11 | GP11 | 15 | 26 | GP20 | 20 |
12 | GP12 | 16 | 25 | GP19 | 19 |
13 | GP13 | 17 | 24 | GP18 | 18 |
GND | 18 | 23 | GND | ||
14 | GP14 | 19 | 22 | GP17 | 17 |
15 | GP15 | 20 | 21 | GP16 | 16 |
25 | GP25 | LED |
DuoS
DuoS 的 wiringX 引脚序号, 与物理引脚序号是一致的,蓝色 LED 控制引脚不在引出的 40PIN 物理引脚上,其 wiringX 的序号是 0
。
排针 J3
排针 J3
上的 GPIO 使用 3.3V 逻辑电平。
wiringX | PIN NAME | PIN# | PIN# | PIN NAME | wiringX |
---|---|---|---|---|---|
3V3 | 1 | 2 | VSYS(5V) | ||
3 | B20 | 3 | 4 | VSYS(5V) | |
5 | B21 | 5 | 6 | GND | |
7 | B18 | 7 | 8 | A16 | 8 |
GND* | 9 | 10 | A17 | 10 | |
11 | B11 | 11 | 12 | B19 | 12 |
13 | B12 | 13 | 14 | GND | |
15 | B22 | 15 | 16 | A20 | 16 |
3V3 | 17 | 18 | A19 | 18 | |
19 | B13 | 19 | 20 | GND | |
21 | B14 | 21 | 22 | A18 | 22 |
23 | B15 | 23 | 24 | B16 | 24 |
GND | 25 | 26 | A28 | 26 |
GND*:引脚 9 在 DuoS V1.1 版本硬件中是一个低电平的 GPIO,在 V1.2 及更高版本硬件中为 GND。
排针 J4
排针 J4
上的 GPIO 使用 1.8V 逻辑电平。
该排针上的大部分引脚都有其专用功能,如 MIPI DSI 信号,触摸屏信号以及音频信号,如非特殊需求,不建议使用该排针上的引脚做为 GPIO 使用。
wiringX | PIN NAME | PIN# | PIN# | PIN NAME | wiringX |
---|---|---|---|---|---|
VSYS(5V) | 52 | 51 | AUDIO_OUT_R | ||
50 | B1 | 50 | 49 | AUDIO_OUT_L | |
48 | B2 | 48 | 47 | AUDIO_IN_R | |
46 | B3 | 46 | 45 | AUDIO_IN_L | |
44 | E2 | 44 | 43 | 3V3 | |
42 | E1 | 42 | 41 | C18 | 41 |
40 | E0 | 40 | 39 | C19 | 39 |
GND | 38 | 37 | GND | ||
36 | C20 | 36 | 35 | C16 | 35 |
34 | C21 | 34 | 33 | C17 | 33 |
GND | 32 | 31 | GND | ||
30 | C14 | 30 | 29 | C12 | 29 |
28 | C15 | 28 | 27 | C13 | 27 |
开发环境配置
准备开发环境
使用本地的 Ubuntu 系统,推荐 Ubuntu 22.04 LTS (也可以使用虚拟机中的 Ubuntu 系统、Windows 中 WSL 安装的 Ubuntu、基于 Docker 的 Ubuntu 系统)。
-
安装编译依赖的工具
sudo apt-get install wget git make
-
获取 Examples 源码
git clone https://github.com/milkv-duo/duo-examples.git
-
加载编译环境
cd duo-examples
source envsetup.sh第一次加载会自 动下载所需的编译工具链,下载后的目录名为
host-tools
,下次再加载编译环境时,会检测该目录,如果已存在则不会再次下载。加载编译环境时需要按提示输入所需编译目标:
Select Product:
1. Duo (CV1800B)
2. Duo256M (SG2002) or DuoS (SG2000)如果目标板是 Duo 则选择
1
,如果目标板是 Duo256M 或者 DuoS 则选择2
。由于 Duo256M 和 DuoS 支持 RISCV 和 ARM 两种架构,还需要按提示继续选择:Select Arch:
1. ARM64
2. RISCV64
Which would you like:如果测试程序需要在 ARM 系统中运行,选择
1
,如果是 RISCV 系统则选择2
。 -
编译测试
以
hello-world
为例,进入该例子目录直接执行make
即可:cd hello-world
make编译成功后将生成的
helloworld
可执行程序通过网口或者 USB 网络等方式传送到 Duo 设备中,比如默认固件支持的 USB-NCM 方式,Duo 的 IP 为192.168.42.1
,用户名是root
,密码是milkv
。scp helloworld [email protected]:/root/
发送成功后,在 ssh 或者串口登陆的终端中运行
./helloworld
,会打印Hello, World!
[root@milkv]~# ./helloworld
Hello, World!至此,我们的编译开发环境就可以正常使用了
如何创建自己的工程
根据需要,拷贝现有的例子,稍加修改即可。比如需要操作某个 GPIO,可以参考blink
例子,LED闪烁就是通过控制 GPIO 电平高低实现的,平台初始化和控制 GPIO 的方法,可参考blink.c
中的代码。
- 新建自己的工程目录
my-project
- 复制
blink
例子中的blink.c
和Makefile
文件到my-project
目录 - 将
blink.c
重命名为自己所需名字如gpio_test.c
- 修改
Makefile
中的TARGET=blink
为TARGET=gpio_test
- 修改
gpio_test.c
,实现自己的代码逻辑 - 执行
make
命令编译 - 将生成的
gpio_test
可执行程序发送到Duo中运行
注意:
- 新建工程目录不是必须要放到 duo-examples 目录下的,可以根据自己的习惯放到其他位置,执行 make 编译命令之前,加载过 duo-examples 目录下的编译环境就可以了(
source /PATH/TO/duo-examples/envsetup.sh
)。 - 在加载过编译环境(
envsetup.sh
)的终端里,不要编译其他平台如 ARM 或 X86 的 Makefile 工程,如需编译其他平台项目,需要新开终端。
代码示范
GPIO 使用示例
下面是一个操作 GPIO 的例子,将 Duo 的20
引脚间隔1秒循环拉高再拉低,物理20
引脚的 wiringX 序号是15
。
#include <stdio.h>
#include <unistd.h>
#include <wiringx.h>
int main() {
int DUO_GPIO = 15;
// Duo: milkv_duo
// Duo256M: milkv_duo256m
// DuoS: milkv_duos
if(wiringXSetup("milkv_duo", NULL) == -1) {
wiringXGC();
return -1;
}
if(wiringXValidGPIO(DUO_GPIO) != 0) {
printf("Invalid GPIO %d\n", DUO_GPIO);
}
pinMode(DUO_GPIO, PINMODE_OUTPUT);
while(1) {
printf("Duo GPIO (wiringX) %d: High\n", DUO_GPIO);
digitalWrite(DUO_GPIO, HIGH);
sleep(1);
printf("Duo GPIO (wiringX) %d: Low\n", DUO_GPIO);
digitalWrite(DUO_GPIO, LOW);
sleep(1);
}
return 0;
}
编译后放到 Duo 中运行,可以用万用表或者示波器测量20
引脚的状态是否符合预期。
也可以使用板上的 LED 引脚来验证,通过观察 LED 亮灭来直观地判断程序是否正确执行,LED 引脚的 wiringX 序号为25
,把上面代码中的15
引脚改为25
即可,需要注意的是默认固件开机后通过脚本控制 LED 闪烁了,要将其禁用,方法请参考下面的 blink 例子说明。
I2C 使用示例
以下是一个 I2C 的示例:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <wiringx.h>
#define I2C_DEV "/dev/i2c-1"
#define I2C_ADDR 0x04
int main(void)
{
int fd_i2c;
int data = 0;
// Duo: milkv_duo
// Duo256M: milkv_duo256m
// DuoS: milkv_duos
if(wiringXSetup("milkv_duo", NULL) == -1) {
wiringXGC();
return -1;
}
if ((fd_i2c = wiringXI2CSetup(I2C_DEV, I2C_ADDR)) <0) {
printf("I2C Setup failed: %d\n", fd_i2c);
wiringXGC();
return -1;
}
// TODO
}