外设与接口
硬件资源图
序号 | 接口 | 序号 | 接口 |
---|---|---|---|
1 | RTC 电池接口 | 10 | 电源 Type-C 接口 |
2 | Micro USB (UART 调试) | 11 | PWR 按键 |
3 | TurboX C6490P SOM | 12 | EDL 按键 |
4 | 3.5mm 耳机接口 | 13 | 摄像头接口 2 |
5 | USB Type-C with DP (USB 3.1) | 14 | 摄像头接口 1 |
6 | USB Type-A (USB 2.0) | 15 | Wi-Fi/蓝牙模块 |
7 | 2 x USB Type-A (USB 3.0) | 16 | 风扇接口 |
8 | 1000M 以太网 | 17 | 40-pin 连接器 |
9 | HDMI OUT | 18 | M.2 Key M 接口 |
40 pin 连接器
GPIO
RUBIK Pi 3 适配了 WiringRP(基于高性能 GPIO 编程库 WiringPi),推荐使用 WiringRP 来对 GPIO 进行控制和编程。关于 WiringRP 详细信息可访问 https://github.com/rubikpi-ai/WiringRP 查看。
引脚分布
下图是 RUBIK Pi 3 40-pin 连接器的引脚默认功能,其中大部分引脚和树梅派 40-pin 连接器引脚的默认功能兼容。
下表是 40-pin连接器支持的所有功能,图中蓝色字体表明默认功能。
使用 shell 命令控制
在 RUBIK Pi 3 中执行下面的步骤控制 GPIO。
-
使用 WiringRP 相关命令
-
查看 GPIO 状态
gpio readall
-
设置 GPIO 模式
gpio mode 15 in # 将15 号引脚模式置为输入
gpio pins # 查看更改之后的状态
gpio mode 15 out # 将15号引脚模式置为输出
gpio pins # 查看更改之后的状态 -
设置引脚电平
gpio write 15 1 # 将15号引脚置为高电平
gpio read 15 # 读取更改后引脚状态
gpio write 15 0 # 将15号引脚置为低电平
gpio read 15 # 读取更改后引脚状 态
-
-
操作 /sys/class/gpio 下相关节点
GPIO 子系统的编号如下表。
- 进入 /sys/class/gpio 目录:
cd /sys/class/gpio
- 将要控制的 GPIO 导出,如控制 13 号引脚 GPIO_24:
echo 559 > export
- 进入到 gpio559 目录设置 GPIO 属性:
cd gpio559
ls- direction(方向):
- 输入:in
- 输出:out
- value(值):
- 低电平:0
- 高电平:1
- edge (中断边沿):
- 上升沿触发:rising
- 下降沿触发:falling
- 双边沿触发:both
- 禁用中断:none
如设置 13 号引脚输出高电平:
echo out > direction
echo 1 > value取消导出 13 号引脚到用户空间:
echo 559 > unexport
使用 WiringRP (C) 控制
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
- 以下代码示例,将 13 号引脚设置为输出, 15 号引脚设置为输入,循环检测 15 号引脚的电平状态:
#include <stdio.h>
#include <wiringPi.h>
int main (void)
{
wiringPiSetup () ;
pinMode (13, OUTPUT) ;
pinMode (15, INPUT) ;
for (;;)
{
digitalWrite (13, HIGH) ; // On
printf("%d\n", digitalRead (15)); // On
delay (1000) ; // mS
digitalWrite (13, LOW) ; // Off
printf("%d\n", digitalRead (15)); // On
delay (1900) ;
}
return 0 ;
}
-
在 RUBIK Pi 3 中编译程序
adb push gpio.c /opt
adb shell
cd /opt
gcc gpio.c -o gpio -lwiringPi -
将 13 和 15 号引脚使用杜邦线短接,测试 GPIO 电平控制和电平读取情况,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./gpio程序运行结果如下:
使用 WiringRP-Python 控制
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
下方截取代码是使用 WiringRP 库操作 GPIO 的示例,其中将 13 号引脚设置为输出,15 号引脚设置为输入,循环检测 15 号引脚的电平状态。
import wiringpi
import time
wiringpi.wiringPiSetup()
wiringpi.pinMode(13, 1)
wiringpi.pinMode(15, 0)
wiringpi.digitalRead(15)
while True:
wiringpi.digitalWrite(13,1)
pin_level = wiringpi.digitalRead(15)
print(f"in_gpio level: {pin_level}")
time.sleep(1)
wiringpi.digitalWrite(13,0)
pin_level = wiringpi.digitalRead(15)
print(f"in_gpio level: {pin_level}")
time.sleep(1) -
将 gpio.py 传输到 RUBIK Pi 3 中,如使用 ADB 传输。
adb push gpio.py /opt
-
将 13 和 15 号引脚使用杜邦线短接,测试 GPIO 电平控制和电平读取情况,如下图所示
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
python3 gpio.py程序运行结果如下:
使用 Python 程序控制
-
使用 Python 的 periphery 库控制 GPIO,需先在 RUBIK Pi 3 中使用下面命令安装 python-periphery:
pip3 install python-periphery
-
下方截取代码是使用 periphery 库操作 GPIO 的示例,其中将 13 号引脚设置为输出,15 号引脚设置为输入,循环检测 15 号引脚的电平状态。
from periphery import GPIO
import time
out_gpio = GPIO(559, "out")
in_gpio = GPIO(560, "in")
try:
while True:
try:
out_gpio.write(True)
pin_level = in_gpio.read()
print(f"in_gpio level: {pin_level}")
out_gpio.write(False)
pin_level = in_gpio.read()
print(f"in_gpio level: {pin_level}")
time.sleep(1)
except KeyboardInterrupt:
out_gpio.write(False)
break
except IOError:
print("Error")
finally:
out_gpio.close()
in_gpio.close() -
将 gpio.py 传输到 RUBIK Pi 3 中,如使用 ADB 传输。
adb push gpio.py /opt
-
将 13 和 15 号引脚使用杜邦线短接,测试 GPIO 电平控制和电平读取情况,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
python3 gpio.py程序运行结果如下:
使用 C 语言程序控制
-
以下代码示例将 13 号引脚设置为输 出,15 号引脚设置为输入,循环检测 15 号引脚的电平状态:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int out_gpio = 559;
int in_gpio = 560;
int main() {
char export_path[50] = {};
char export_command[100] = {};
snprintf(export_path, sizeof(export_path), "/sys/class/gpio/export");
snprintf(export_command, sizeof(export_command), "echo %d > %s ", out_gpio, export_path);
system(export_command);
snprintf(export_command, sizeof(export_command), "echo %d > %s ", in_gpio, export_path);
system(export_command);
char direction_path[50] = {};
snprintf(direction_path, sizeof(direction_path), "/sys/class/gpio/gpio%d/direction", out_gpio);
FILE *direction_file = fopen(direction_path, "w");
if (direction_file == NULL) {
perror("Failed to open GPIO direction file");
return -1;
}
fprintf(direction_file, "out");
fclose(direction_file);
snprintf(direction_path, sizeof(direction_path), "/sys/class/gpio/gpio%d/direction", in_gpio);
direction_file = fopen(direction_path, "w");
if (direction_file == NULL) {
perror("Failed to open GPIO direction file");
return -1;
}
fprintf(direction_file, "in");
fclose(direction_file);
char value_in_path[50] = {};
char value_out_path[50] = {};
char cat_command[100] = {};
snprintf(value_out_path, sizeof(value_out_path), "/sys/class/gpio/gpio%d/value", out_gpio);
snprintf(value_in_path, sizeof(value_in_path), "/sys/class/gpio/gpio%d/value", in_gpio);
snprintf(cat_command, sizeof(cat_command), "cat %s", value_in_path);
FILE *value_out_file = fopen(value_out_path, "w");
if (value_out_file == NULL) {
perror("Failed to open GPIO value file");
return -1;
}
for (int i = 0; i < 5; i++) {
fprintf(value_out_file, "1");
fflush(value_out_file);
system(cat_command);
sleep(1);
fprintf(value_out_file, "0");
fflush(value_out_file);
system(cat_command);
sleep(1);
}
fclose(value_out_file);
char unexport_path[50] = {};
char unexport_command[100] = {};
snprintf(unexport_path, sizeof(unexport_path), "/sys/class/gpio/unexport");
snprintf(unexport_command, sizeof(unexport_command), "echo %d > %s ", out_gpio, unexport_path);
system(unexport_command);
snprintf(unexport_command, sizeof(unexport_command), "echo %d > %s ", in_gpio, unexport_path);
system(unexport_command);
return 0;
} -
编译程序:
-
交叉编译,具体可参考 交叉编译工具使用方法章节:
aarch64-qcom-linux-gcc gpio.c -o gpio --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
若使用了交叉编译,需将 gpio 传输到 RUBIK Pi 3 中,如使用 ADB 传输:
adb push gpio /opt
-
在 RUBIK Pi 3 中编译:
adb push gpio.c /opt
adb shell
cd /opt
gcc gpio.c -o gpio
-
-
将 13 和 15 号引脚使用杜邦线短接,测试 GPIO 电平控制和电平读取情况,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./gpio程序运行结果如下:
I2C
I2C 是飞利浦公司在 20 世纪 80 年代开发的一种双向 2 线制总线,用于实现高效的 IC 间控制总线。总线上的每个设备都有其唯一的地址(由飞利浦公司领导的 I2C 总机构注册)。I2C 核心支持多控制器模式,以及 10 位目标地址和 10 位可扩展地址。关于 I2C 的更多信息,请参阅 https://www.i2c-bus.org/fileadmin/ftp/i2c_bus_specification_1995.pdf。
RUBIK Pi 3 适配了 WiringRP(基于高性能 GPIO 编程库 WiringPi )。推荐使用 WiringRP 对 I2C 进行控制和编程。关于 WiringRP 详细信息可访问 https://github.com/rubikpi-ai/WiringRP 查看。
引脚分布
下图是 RUBIK Pi 3 40-pin 连接器的引脚默认功能,其中大部分引脚和树梅派 40-pin 连接器引脚的默认功能兼容。
3 号引脚和 5 号引脚默认已设置配为 I2C1。
下表是 40-pin 连接器支持的所有功能,图中蓝色字体表明默认功能。
使用 shell 命令测试
在 RUBIK Pi 3 中执行下面步骤控制 I2C 总线。
-
使用 WiringRP 相关命令:
./gpio -x ads1115:100:10 aread 100 #通过 I2C 总线读取 ADS1115 设备的模拟信号值
-
使用 i2cdetect 工具
-
查看 I2C1 接口上的设备:
i2cdetect -a -y -r 1
-
读取地址为 0x38 设备的全部寄存器:
i2cdump -f -y 1 0x38
-
向地址为 0x38 设备的 0x01 寄存器地址写入 0xaa:
i2cset -f -y 1 0x38 0x01 0xaa
-
读取地址为 0x38 的设备,寄存器地址为0x01处的数值:
i2cget -f -y 1 0x38 0x01
-
使用 WiringRP (C) I2C 通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例,I2C1 总线和地址为 0x38 的设备进行通信,向设备 0x01 地址处写入 0xaa:
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define I2C_ADDRESS 0x38
int main(void)
{
int fd;
if (wiringPiSetup() == -1) {
exit(1);
}
fd = wiringPiI2CSetup(1, I2C_ADDRESS);
if (fd == -1) {
exit(1);
}
unsigned char data[2];
if (read(fd, data, 2) != 2) {
exit(1);
}
wiringPiI2CWriteReg8(fd, 0x01, 0xaa) ;
close(fd);
return 0;
} -
在 RUBIK Pi 3 中编译程序
adb push gpio.c /opt
adb shell
cd /opt
gcc i2c.c -o i2c -lwiringPi -
将 3 和 5 号引脚连接 I2C 传感器,验证 I2C 总线通信,如下图所示
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令运行程序:
cd /opt
./i2c
使用 WiringRP-Python I2C 通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例,使用 I2C1 总线和地 址为 0x38 的设备进行通信,向设备 0x01 地址处写入 0xaa:
import wiringpi as wpi
wpi.wiringPiSetup()
fd=wpi.wiringPiI2CSetup(0x38, 1)
wpi.wiringPiI2CWriteReg8 (fd, 0x01, 0xaa) -
将 i2c.py 传输到 RUBIK Pi 3 中,如使用 ADB 传输。
adb push i2c.py /opt
-
将 3 和 5 号引脚连接 I2C 传感器,验证 I2C 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
python3 i2c.py
使用 Python 程序 I2C 通信
-
使用 Python 的 smbus 库控制 I2C,需先在 RUBIK Pi 3 中使用下面命令安装 smbus 库:
pip3 install smbus
-
以下代码示例,使用 I2C1 总线和地址为 0x38 的设备进行通信,向设备 0x01 地址处写入 0xaa:
import smbus
def main():
data = [0x01, 0xaa]
try:
i2c_bus = smbus.SMBus(1)
print("i2cdetect addr : ", end="")
for address in range(0x7F):
try:
i2c_bus.write_i2c_block_data(address, 0, data)
print("0x{:02X},".format(address), end="")
except OSError:
pass
print()
except Exception as e:
print(f"An error occurred: {e}")
finally:
if i2c_bus:
i2c_bus.close()
if __name__ == "__main__":
main() -
将 i2c.py 传输到 RUBIK Pi 3中,如果使用 ADB 传输,命令如下:
adb push i2c.py /opt
-
将 3 和 5 号引脚连接 I2C 传感器,验证 I2C 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
python3 i2c.py程序运行结果如下:
使用 C 语言程序 I2C 通信
-
以下代码示例,I2C1 总线和地址为 0x38 的设备进行通信,向设备 0x01 地址处写入 0xaa:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_DEVICE_PATH "/dev/i2c-1"
int main() {
uint8_t data[2] = {0x01,0xaa};
const char *i2c_device = I2C_DEVICE_PATH;
int i2c_file;
if ((i2c_file = open(i2c_device, O_RDWR)) < 0) {
perror("Failed to open I2C device");
return -1;
}
ioctl(i2c_file, I2C_TENBIT, 0);
ioctl(i2c_file, I2C_RETRIES, 5);
printf("i2cdetect addr : ");
for (int x = 0; x < 0x7f; x++)
{
if (ioctl(i2c_file, I2C_SLAVE, x) < 0) {
perror("Failed to set I2C slave address");
close(i2c_file);
return -1;
}
if (write(i2c_file, data, 2) == 2)
{
printf("0x%x,", x);
}
}
close(i2c_file);
printf("\r\n");
return 0;
} -
编译程序:
-
交叉编译,具体可参考 交叉编译工具使用方法 章节:
aarch64-qcom-linux-gcc i2c.c -o i2c --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
若使用的交叉编译,需要将 i2c 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push i2c /opt
-
在 RUBIK Pi 3 中编译
adb push i2c.c /opt
adb shell
cd /opt
gcc i2c.c -o i2c
-
-
将 3 和 5 号引脚连接 I2C 传感器,验证 I2C 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./i2c程序运行结果如下:
SPI
串行外设接口 (SPI) 是在全双工模式下工作的同步串行数据链路。SPI 又称为 4 线制串行总线。
RUBIK Pi 3 适配了 WiringRP(基于高性能 GPIO 编程库 WiringPi),推荐使用 WiringRP 对 SPI 进行控制和编程。关于 WiringRP 详细信息可访问 https://github.com/rubikpi-ai/WiringRP 查看。
引脚分布
下图是 RUBIK Pi 3 40-pin 连接器的引脚默认功能,其中大部分引脚和树梅派 40-pin 连接器引脚的默认功能兼容。
19 号、21 号、23 号、24 号引脚 默认已设置配为 SPI。
下表是 40-pin 连接器支持的所有功能,图中蓝色字体表明默认功能。
使用 WiringRP (C) SPI 通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例使用 SPI 总线进行数据收发通信:
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
unsigned char send_data[64] = "hello world!";
unsigned char read_data[64];
if(wiringPiSetup() == -1)
exit(1);
fd = wiringPiSPISetup(0, 1000000);
if(fd < 0)
exit(2);
printf("\rtx_buffer: \n %s\n ", send_data);
// Send and receive data
if(wiringPiSPIDataRW(0, send_data, sizeof(send_data)) < 0)
exit(3);
printf("\rtx_buffer: \n %s\n ", send_data);
return 0;
} -
在 RUBIK Pi 3 中编译程序
adb push spi.c /opt
adb shell
cd /opt
gcc spi.c -o spi -lwiringPi -
将 19 号引脚和 21 号引脚使用杜邦线短接,验证 SPI 总线通信,如下 图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./spi程序执行结果 如下:
使用 WiringRP-Python SPI通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例使用 SPI 总线进行数据收发通信:
import wiringpi as wpi
wpi.wiringPiSetup()
wpi.wiringPiSPISetup(0, 8000000)
tx_buffer = bytes([72, 101, 108, 108, 111])
print("tx_buffer:\n\r ", tx_buffer)
retlen, rx_buffer = wpi.wiringPiSPIDataRW(0, tx_buffer)
print("rx_buffer:\n\r ", rx_buffer)
-
将 spi.py 传输到 RUBIK Pi 3 中,如使用 ADB 传输。
adb push spi.py /opt
-
将 19 号引脚和 21 号引脚使用杜邦线短接,验证 SPI 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
python3 spi.py
程序执行结果如下:
使用 Python 程序 SPI 通信
-
使用 Python 的 spidev 库进行 SPI 通信,需先在 RUBIK Pi 3 中使用下面命令安装spidev 库:
pip3 install spidev
-
以下代码示例使用 SPI 总线进行数据收发通信:
import spidev
def main():
tx_buffer = [ord(char) for char in "hello world!"]
rx_buffer = [0] * len(tx_buffer)
try:
spi = spidev.SpiDev()
spi.open(12, 0)
spi.max_speed_hz = 1000000
rx_buffer = spi.xfer2(tx_buffer[:])
print("tx_buffer:\n\r", ''.join(map(chr, tx_buffer)))
print("rx_buffer:\n\r", ''.join(map(chr, rx_buffer)))
except Exception as e:
print(f"An error occurred: {e}")
finally:
if spi:
spi.close()
if __name__ == "__main__":
main() -
将 spi.py 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push spi.py /opt
-
将 19 号引脚和 21 号引脚使用杜邦线短接,验证 SPI 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
python3 spi.py
程序执行结果如下:
使用 C 语言程序 SPI 通信
-
以下代码示例使用 SPI 总线进行数据收发通信:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#define SPI_DEVICE_PATH "/dev/spidev12.0"
int main() {
int spi_file;
uint8_t tx_buffer[50] = "hello world!";
uint8_t rx_buffer[50];
// Open the SPI device
if ((spi_file = open(SPI_DEVICE_PATH, O_RDWR)) < 0) {
perror("Failed to open SPI device");
return -1;
}
// Configure SPI mode and bits per word
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
if (ioctl(spi_file, SPI_IOC_WR_MODE, &mode) < 0) {
perror("Failed to set SPI mode");
close(spi_file);
return -1;
}
if (ioctl(spi_file, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
perror("Failed to set SPI bits per word");
close(spi_file);
return -1;
}
// Perform SPI transfer
struct spi_ioc_transfer transfer = {
.tx_buf = (unsigned long)tx_buffer,
.rx_buf = (unsigned long)rx_buffer,
.len = sizeof(tx_buffer),
.delay_usecs = 0,
.speed_hz = 1000000, // SPI speed in Hz
.bits_per_word = 8,
};
if (ioctl(spi_file, SPI_IOC_MESSAGE(1), &transfer) < 0) {
perror("Failed to perform SPI transfer");
close(spi_file);
return -1;
}
/* Print tx_buffer and rx_buffer*/
printf("\rtx_buffer: \n %s\n ", tx_buffer);
printf("\rrx_buffer: \n %s\n ", rx_buffer);
// Close the SPI device
close(spi_file);
return 0;
} -
编译程序:
-
交叉编译,具体可参考 交叉编译工具使用方法章节:
aarch64-qcom-linux-gcc spi.c -o spi --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
若使用交叉编译,需要将 spi 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push spi /opt
-
在 RUBIK Pi 3 中编译
adb push spi.c /opt
adb shell
cd /opt
gcc spi.c -o spi
-
-
将 19 号引脚和 21 号引脚使用杜邦线短接,验证 SPI 总线通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./spi程序执行结果如下:
UART
RUBIK Pi 3 适配了 WiringRP(基于高性能 GPIO 编程库 WiringPi),推荐使用 WiringRP 对 UART 进行控制和编程。关于 WiringRP 详细信息可访问 https://github.com/rubikpi-ai/WiringRP 查看。
引脚分布
下图是 RUBIK Pi 3 40-pin 连接器的引脚默认功能,其中大部分引脚和树梅派 40-pin 连接器引脚的默认功能兼容。
8 号和 10 号引脚默认已设置配为 UART,设备节点为 /dev/ttyHS2。
下表是 40-pin 连接器支持的 所有功能,图中蓝色字体表明默认功能。
使用 shell 命令测试
在 RUBIK Pi 3 中 使用下面命令控制串口通信
-
使用 stty 工具配置串口,如下将串口的输入速率和输出速率都设置为 115200,并关闭回显:
stty -F /dev/ttyHS2 ispeed 115200 ospeed 115200
stty -F /dev/ttyHS2 -echo -
在 RUBIK Pi 3 上开启两个终端,将 8 号引脚和 10 号引脚使用杜邦线短接,分别执行下面命令,接收端会回 显发送端的内容:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
echo "hello world!" > /dev/ttyHS2 # 发送端
cat /dev/ttyHS2 # 接收端
使用 WiringRP (C) UART通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例使用 UART 进行数据收发通信:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main ()
{
int fd ;
int count ;
unsigned int nextTime ;
if ((fd = serialOpen ("/dev/ttyHS2", 115200)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiSetup () == -1)
{
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
char tx_buffer[] = "hello world!\n";
for (count = 0 ; count < sizeof(tx_buffer) ; count++)
{
serialPutchar (fd, tx_buffer[count]) ;
delay (3) ;
printf ("%c", serialGetchar (fd)) ;
}
printf ("\n") ;
return 0 ;
} -
编译程序:
-
在 RUBIK Pi 3 中编译
adb push uart.c /opt
adb shell
cd /opt
gcc uart.c -o uart
-
-
将 8 号引脚和 10 号引脚使用杜邦线短接,验证串口通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./uart程序执行结果如下:
使用 WiringRP-Python UART 通信
WiringRP 库中提供了一系列的 API 函数,用更少的逻辑实现控制。
-
以下代码示例使用 UART 进行数据收发通信:
import wiringpi
serial = wiringpi.serialOpen('/dev/ttyHS2', 115200)
wiringpi.serialPuts(serial, "hello world")
received_data = []
c = wiringpi.serialGetchar(serial);
received_data.append(chr(c))
cnt = wiringpi.serialDataAvail(serial);
for i in range(cnt):
c = wiringpi.serialGetchar(serial);
received_data.append(chr(c))
print("Received:", received_data)
wiringpi.serialClose(serial) -
将 uart.py 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push uart.py /opt
-
将 8 号引脚和 10 号引脚使用杜邦线短接,验证串口通信,如下图所示:
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
python3 uart.py
程序执行结果如下:
使用 Python 程序 UART 通信
-
使用 Python 的 serial 库进行 UART 通信,需先在 RUBIK Pi 3 中使用下面命令安装 serial 库:
pip3 install pyserial
-
以下代码示例使用 UART 进行数据收发通信:
import serial
import time
with serial.Serial(
"/dev/ttyHS2",
baudrate=115200,
bytesize=serial.EIGHTBITS,
stopbits=serial.STOPBITS_ONE,
parity=serial.PARITY_NONE,
timeout=1,
) as uart3:
uart3.write(b"Hello World!\n")
buf = uart3.read(128)
print("Raw data:\n", buf)
data_strings = buf.decode("utf-8")
print("Read {:d} bytes, printed as string:\n {:s}".format(len(buf), data_strings)) -
将 uart.py 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push uart.py /opt
-
将 8 号引脚和 10 号引脚使用杜邦线短接,验证串口通信,如下图所示
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
python3 uart.py
程序执行结果如下:
使用 C 语言程序 UART 通信
-
以下代码示例使用 UART 进行数据收发通信:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int main() {
int serial_port_num = 2;
char serial_port[15];
sprintf(serial_port,"/dev/ttyHS%d",serial_port_num);
int serial_fd;
serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
if (serial_fd == -1) {
perror("Failed to open serial port");
return 1;
}
struct termios tty;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(serial_fd, &tty) != 0) {
perror("Error from tcgetattr");
return 1;
}
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
perror("Error from tcsetattr");
return 1;
}
char tx_buffer[] = "hello world!\n";
ssize_t bytes_written = write(serial_fd, tx_buffer, sizeof(tx_buffer));
if (bytes_written < 0) {
perror("Error writing to serial port");
close(serial_fd);
return 1;
}
printf("\rtx_buffer: \n %s ", tx_buffer);
char rx_buffer[256];
int bytes_read = read(serial_fd, rx_buffer, sizeof(rx_buffer));
if (bytes_read > 0) {
rx_buffer[bytes_read] = '\0';
printf("\rrx_buffer: \n %s ", rx_buffer);
} else {
printf("No data received.\n");
}
close(serial_fd);
return 0;
} -
编译程序:
-
交叉编译,具体可参考交叉编译工具使用方法章节:
aarch64-qcom-linux-gcc uart.c -o uart --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
若使用交叉编译,需要将 uart 传输到 RUBIK Pi 3 中,如果使用 ADB 传输,命令如下:
adb push uart /opt
-
在 RUBIK Pi 3 中编译
adb push uart.c /opt
adb shell
cd /opt
gcc uart.c -o uart
-
-
将 8 号引脚和 10 号引脚使用杜邦线短接,验证串口通信,如下图所示
注意注意引脚顺序,请勿将电源和地引脚短接,否则可能会造成板子损坏。
运行如下命令:
cd /opt
./uart程序执行结果如下:
USB
RUBIK Pi 3 拥有 4 个 USB 口:
-
两个 USB 3.0 口,只能作为主机模式使用,如下图 7。
-
一个 USB 2.0 口,可以作为主机或设备模式使用,如下图 6。
-
一个 USB 3.1 Gen 1 口,可以作为主机或设备模式(ADB),以及 DP 显示使用,如下图 5。
USB 2.0 Type-A 接口
USB 2.0 接口默认为主机模式,作为设备模式时需要手动执行命令切换,如下为一种切换方式,在 RUBIK Pi 3 中输入下面命令,将 RUBIK Pi 3 模拟为 U 盘:
cd /sys/kernel/config/usb_gadget/ #在串口终端登录,执行下面命令
mkdir g1
cd g1
mkdir functions/mass_storage.0
dd if=/dev/zero of=/tmp/test.iso bs=1M count=2048 #创建大小为2G的U盘空间
mkfs.ext4 /tmp/test.iso
echo "/tmp/test.iso" > functions/mass_storage.0/lun.0/file
mkdir configs/c.1
ln -s functions/mass_storage.0/ configs/c.1/f3
mount -t debugfs none /sys/kernel/debug/
echo device > /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode #将USB切换为device模式
echo 8c00000.usb > UDC #连接USB线,U盘被识别 可在U盘内写入和写出文件
echo host > /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode #拔掉USB线,切换为主机模式
USB 3.1 Type-C 接口
Type-C 接口可自动完成主机和设备模式的切换。
-
当 Type-C 接入 PC 时自动切换为设备模式。
-
接入 OTG 线时自动切换为主机模式。
-
接入 DP 显示器时,自动输出 DP 视频信号。
USB 调试
本节提供有关获取调试日志的各种方法的信息。调试方式有 regdumps
、调试 ftraces
、 configfs
节点等。在调试与进入/退出低功耗模式、SMMU 故障、无时钟访问相关的问题时,可通过上述日志查看事件和控制器状态的详细信息。
-
USB 2.0 Type-A 设备路径: /sys/devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1
-
USB 3.0 Type-A 设备路径:
-
/sys/devices/platform/soc@0/1c00000.pci/pci0000:00/0000:00:00.0/0000:01:00.0/usb2
-
/sys/devices/platform/soc@0/1c00000.pci/pci0000:00/0000:00:00.0/0000:01:00.0/usb3
-
-
USB 3.1 Type-C 设备路径:/sys/devices/platform/soc@0/a600000.usb
USB 跟踪
使用 debugfs
跟踪可以更加深入地了解 USB 线上发生的每一个事务。如需查看跟踪列表,可运行以下命令。
确保已挂载
debugfs
。如果尚未挂载,可运行以下命令来挂载debugfs
:
mount -t debugfs none /sys/kernel/debug
ls /sys/kernel/debug/tracing/events/dwc3
以下是可用于验证 xHCI/gadget 协议栈/USB Type-C 连接器系统软件接口 (UCSI) 中的数据传输的跟踪。
dwc3_alloc_request dwc3_event dwc3_gadget_generic_cmd enable
dwc3_complete_trb dwc3_free_request dwc3_gadget_giveback filter
dwc3_ctrl_req dwc3_gadget_ep_cmd dwc3_prepare_trb
dwc3_ep_dequeue dwc3_gadget_ep_disable dwc3_readl
dwc3_ep_queue dwc3_gadget_ep_enable dwc3_writel
要列出 xHCI/主机控制器驱动程序 (HCD) 中的跟踪数据,请运行以下命令。
ls /sys/kernel/debug/tracing/events/xhci-hcd
以下是可用于验证 xHCI/HCD 中数据传输的跟踪。
enable xhci_handle_cmd_config_ep
filter xhci_handle_cmd_disable_slot
xhci_add_endpoint xhci_handle_cmd_reset_dev
xhci_address_ctrl_ctx xhci_handle_cmd_reset_ep
xhci_address_ctx xhci_handle_cmd_set_deq
xhci_alloc_dev xhci_handle_cmd_set_deq_ep
xhci_alloc_virt_device xhci_handle_cmd_stop_ep
xhci_configure_endpoint xhci_handle_command
xhci_configure_endpoint_ctrl_ctx xhci_handle_event
xhci_dbc_alloc_request xhci_handle_port_status
xhci_dbc_free_request xhci_handle_transfer
xhci_dbc_gadget_ep_queue xhci_hub_status_data
xhci_dbc_giveback_request xhci_inc_deq
xhci_dbc_handle_event xhci_inc_enq
xhci_dbc_handle_transfer xhci_queue_trb
xhci_dbc_queue_request xhci_ring_alloc
xhci_dbg_address xhci_ring_ep_doorbell
xhci_dbg_cancel_urb xhci_ring_expansion
xhci_dbg_context_change xhci_ring_free
xhci_dbg_init xhci_ring_host_doorbell
xhci_dbg_quirks xhci_setup_addressable_virt_device
xhci_dbg_reset_ep xhci_setup_device
xhci_dbg_ring_expansion xhci_setup_device_slot
xhci_discover_or_reset_device xhci_stop_device
xhci_free_dev xhci_urb_dequeue
xhci_free_virt_device xhci_urb_enqueue
xhci_get_port_status xhci_urb_giveback
xhci_handle_cmd_addr_dev
请运行以下命令,以便列出 USB 视频类 (UVC) gadget 驱动程序的可用事件。
ls /sys/kernel/debug/tracing/events/gadget
随即显示以下输出。
enable usb_gadget_activate
filter usb_gadget_clear_selfpowered
usb_ep_alloc_request usb_gadget_connect
usb_ep_clear_halt usb_gadget_deactivate
usb_ep_dequeue usb_gadget_disconnect
usb_ep_disable usb_gadget_frame_number
usb_ep_enable usb_gadget_giveback_request
usb_ep_fifo_flush usb_gadget_set_remote_wakeup
usb_ep_fifo_status usb_gadget_set_selfpowered
usb_ep_free_request usb_gadget_vbus_connect
usb_ep_queue usb_gadget_vbus_disconnect
usb_ep_set_halt usb_gadget_vbus_draw
usb_ep_set_maxpacket_limit usb_gadget_wakeup
usb_ep_set_wedge
如需列出 UCSI 驱动程序中的可用事件,可运行以下命令。
ls /sys/kernel/debug/tracing/events/ucsi
随即显示以下输出。
enable ucsi_connector_change ucsi_register_port ucsi_run_command
filter ucsi_register_altmode ucsi_reset_ppm
USB 寄存器打印
USB debugfs
提供以下信息,下面以 Type-C 接口为例。
-
工作模式
cat /sys/kernel/debug/usb/a600000.usb/mode # Type-C 接口
备注USB 2.0 Type-A 的工作模式
cat /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode
示例输出:
device
-
设备模式下所有端点的状态和传输环形缓冲区 (TRB) 队列。
-
当前链路状态。
cat /sys/kernel/debug/usb/a600000.usb/link_state
示例输出
Sleep
-
列出处理器 (LSP) dump。
cat /sys/kernel/debug/usb/a600000.usb/lsp_dump
示例输出:
GDBGLSP[0] = 0x40000000
GDBGLSP[1] = 0x00003a80
GDBGLSP[2] = 0x38200000
GDBGLSP[3] = 0x00802000
GDBGLSP[4] = 0x126f1000
GDBGLSP[5] = 0x3a800018
GDBGLSP[6] = 0x00000a80
GDBGLSP[7] = 0xfc03f14a
GDBGLSP[8] = 0x0b803fff
GDBGLSP[9] = 0x00000000
GDBGLSP[10] = 0x000000f8
GDBGLSP[11] = 0x000000f8
GDBGLSP[12] = 0x000000f8
GDBGLSP[13] = 0x000000f8
GDBGLSP[14] = 0x000000f8
GDBGLSP[15] = 0x000000f8
ls /sys/kernel/debug/usb/a600000.usb
示例输出:
ep0in ep11out ep14in ep1out ep4in ep6out ep9in regdump
ep0out ep12in ep14out ep2in ep4out ep7in ep9out testmode
ep10in ep12out ep15in ep2out ep5in ep7out link_state
ep10out ep13in ep15out ep3in ep5out ep8in lsp_dump
ep11in ep13out ep1in ep3out ep6in ep8out mode