40-PIN 功能测试
GPIO
GPIO 简介
通用输入/输出(GPIO)是集成电路或电子电路(如 MCU/MPU)电路板上的非专用数字信号引脚,可用作输入或输出,或同时用作输入和输出,并可由软件控制。
准备
- 一块 Radxa ROCK 2F
- 一个 LED 灯
连接
如图所示,连接 Radxa ROCK 2F 的 PIN_3
测试
输入测试
将 3 接地或者接 3.3V,
radxa@rock-2f:~$ gpioget gpiochip4 0
如果接的是地,该命令输出 0,如果接的是 3.3V,该命令输出 1。
输出测试
radxa@rock-2f:~$ sudo gpioset -m signal $(sudo gpiofind PIN_3)=0 # 输出低电平, Led 灭 radxa@rock-2f:~$ sudo gpioset -m signal $(sudo gpiofind PIN_3)=1 # 输出高电平, Led 亮
同一个 GPIO 不允许被两个进程同时使用,否则会提示资源占用。 因此,需要手动按下 'Ctrl + C' 终止后,才可以执行第二个命令。
I2C
I2C 简介
I2C(Inter-Integrated Circuit;发音为 "eye-squared-see "或 "eye-two-see"),又称 I2C 或 IIC,是飞利浦半导体公司于 1982 年发明的一种同步、多控制器/多目标(历史上称为主/从)、单端、串行通信总线。
准备
- 一块 Radxa ROCK 2F
- 一个 OLED
开启 Overlay
请参照设备树配置启用 I2C 相关 Overlay, eg: "Enable I2C0-M1"。
连接
按照以下方式连接 Radxa ROCK 2F 和 OLED
| Radxa ROCK 2F | <--> | OLED |
|---|---|---|
| PIN_5 | <--> | SCL |
| PIN_3 | <--> | SDA |
| PIN_1 | <--> | VCC |
| PIN_9 | <--> | GND |
测试
-
打开终端,在终端中输入以下命令安装 python3-periphery 的 Python 库
-
新建一个名为 Oled.py Python 文件,并将以下代码粘贴到该文件中:
Oled.py
from periphery import I2C
import time
I2C_ADDR = 0x3c
I2C_BUS = "/dev/i2c-8"
i2c = I2C(I2C_BUS)
# SSD1306 init_cmds
init_cmds = [
0xAE, # Display off
0x00, # Set lower column address
0x10, # Set higher column address
0x40, # Set display start line
0xB0, # Set page address
0x81, # Set contrast control
0xCF,
0xA1, # Set segment remap
0xA6, # Normal display
0xA8, # Set multiplex ratio
0x3F,
0xC8, # Set COM output scan direction
0xD3, # Set display offset
0x00,
0xD5, # Set display clock divide ratio/oscillator frequency
0x80,
0xD9, # Set pre-charge period
0xF1,
0xDA, # Set COM pins hardware configuration
0x12,
0xDB, # Set VCOMH deselect level
0x40,
0x8D, # Enable charge pump regulator
0x14,
0xAF # Display on
]
for cmd in init_cmds:
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, cmd])])
def oled_clear():
for page in range(8):
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0xB0 + page])])
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0x00])])
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0x10])])
for _ in range(128):
i2c.transfer(I2C_ADDR, [I2C.Message([0x40, 0x00])])
char_map = {
"H": [0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,],
"R": [0x00, 0x7F, 0x09, 0x19, 0x29, 0x46],
"e": [0x00, 0x38, 0x54, 0x54, 0x54, 0x18],
"l": [0x00, 0x00, 0x41, 0x7F, 0x40, 0x00],
"o": [0x00, 0x38, 0x44, 0x44, 0x44, 0x38],
"r": [0x00, 0x7C, 0x08, 0x04, 0x04, 0x08],
"a": [0x00, 0x20, 0x54, 0x54, 0x54, 0x78],
"d": [0x00, 0x38, 0x44, 0x44, 0x48, 0x7F],
"x": [0x00, 0x44, 0x28, 0x10, 0x28, 0x44]
}
def string_to_bytes(string):
bytes_list = []
for char in string:
bytes_list.extend(char_map.get(char, [0x00] * 4))
bytes_list.append(0x00)
return bytes_list
oled_clear()
hello_world_bytes = string_to_bytes("Hello Radxa")
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0xB0])])
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0x00])])
i2c.transfer(I2C_ADDR, [I2C.Message([0x00, 0x10])])
for byte in hello_world_bytes:
i2c.transfer(I2C_ADDR, [I2C.Message([0x40, byte])])
i2c.close()
该脚本仅为示例,需要根据实际修改变量 I2C_BUS
- 在终端中,执行以下命令进行测试
sudo python3 Oled.py
执行完以上命令后,Oled 会显示 "Hello, Radxa" 的字符
PWM
PWM 简介
脉宽调制(PWM)是一种调制技术,可产生可变宽度的脉冲来表示模拟输入信号的幅度。 对于高振幅信号,输出开关晶体管更多时间处于导通状态,而对于低振幅信号,输出开关晶体管更多时间处于关断状态。
准备
- 一块 Radxa ROCK 2F
- 一个 LED 灯
开启 Overlay
请参照设备树配置启用 PWM 相关 Overlay。
eg: "Enable PWM0_M0"。
连接
如图所示,连接 Radxa ROCK 2F 的 PIN_32
测试
- 打开终端,在终端中输入以下命令安装 python3-periphery 的 Python 库
sudo apt-get install python3-periphery
- 新建一个名为 Pwm_led_test.py 的 Python 文件,并将以下代码粘贴到文件中:
Pwm_led_test.py
#!/usr/bin/env python3
# -- encoding: utf-8 --
from periphery import PWM
import time
step = 0.05
Range = int(1/0.05)
pwmchip = int(input("pwmchip:"))
channel = int(input("channel:"))
pwm = PWM(pwmchip, channel)
try:
pwm.frequency = 1e3
pwm.duty_cycle = 0.00
pwm.enable()
while True:
for i in range(0,Range):
time.sleep(step)
pwm.duty_cycle = round(pwm.duty_cycle+step,2)
if pwm.duty_cycle == 1.5:
time.sleep(1.5)
for i in range(0,Range):
time.sleep(step)
pwm.duty_cycle = round(pwm.duty_cycle-step,2)
except:
print("Error !\n")
finally:
pwm.duty_cycle = 1.0
pwm.close()
- 在终端中,执行以下命令进行测试
radxa@rock-2f:~$ sudo python3 Pwm_led_test.py pwmchip:0 channel:0
执行完以上命令后, Led 会有一个渐变的效果(由暗到亮,由亮到暗)。
SPI
SPI 简介
串行外设接口(SPI)是同步串行通信的实际标准(有许多变体),主要用于嵌入式系统中集成电路之间的短距离有线通信。
准备
- 一块 rock-2f
- 一根母对母杜邦线
开启 Overlay
请参照设备树配置启用 SPIDEV 相关 Overlay, eg: "Enable Enable spidev on SPI0 over CS1"。
连接
如图所示,短接 PIN_19 和 PIN_21
测试
- 打开终端,在终端中输入以下命令安装编译工具
sudo apt-get install build-essential
- 新建一个名为 spidev_test.c 的 C 文件,并将以下代码粘贴到文件中:
spidev_test.c
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev0.0";
static uint32_t mode;
static uint8_t bits = 8;
static char *input_file;
static char *output_file;
static uint32_t speed = 500000;
static uint16_t delay;
static int verbose;
uint8_t default_tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x0D,
};
uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
char *input_tx;
static void hex_dump(const void *src, size_t length, size_t line_size,
char *prefix)
{
int i = 0;
const unsigned char *address = src;
const unsigned char *line = address;
unsigned char c;
printf("%s | ", prefix);
while (length-- > 0) {
printf("%02X ", *address++);
if (!(++i % line_size) || (length == 0 && i % line_size)) {
if (length == 0) {
while (i++ % line_size)
printf("__ ");
}
printf(" | "); /* right close */
while (line < address) {
c = *line++;
printf("%c", (c < 33 || c == 255) ? 0x2E : c);
}
printf("\n");
if (length > 0)
printf("%s | ", prefix);
}
}
}
/*
* Unescape - process hexadecimal escape character
* converts shell input "\x23" -> 0x23
*/
static int unescape(char *_dst, char *_src)
{
int ret = 0;
int match;
char *src = _src;
char *dst = _dst;
unsigned int ch;
while (*src) {
if (*src == '\\' && *(src+1) == 'x') {
match = sscanf(src + 2, "%2x", &ch);
if (!match)
pabort("malformed input string");
src += 4;
*dst++ = (unsigned char)ch;
} else {
*dst++ = *src++;
}
ret++;
}
return ret;
}
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
int out_fd;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
if (mode & SPI_TX_QUAD)
tr.tx_nbits = 4;
else if (mode & SPI_TX_DUAL)
tr.tx_nbits = 2;
if (mode & SPI_RX_QUAD)
tr.rx_nbits = 4;
else if (mode & SPI_RX_DUAL)
tr.rx_nbits = 2;
if (!(mode & SPI_LOOP)) {
if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
tr.rx_buf = 0;
else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
tr.tx_buf = 0;
}
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
if (verbose)
hex_dump(tx, len, 32, "TX");
if (output_file) {
out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (out_fd < 0)
pabort("could not open output file");
ret = write(out_fd, rx, len);
if (ret != len)
pabort("not all bytes written to output file");
close(out_fd);
}
if (verbose || !output_file)
hex_dump(rx, len, 32, "RX");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev0.0)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word\n"
" -i --input input data from a file (e.g. \"test.bin\")\n"
" -o --output output data to a file (e.g. \"results.bin\")\n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n"
" -v --verbose Verbose (show tx buffer)\n"
" -p Send data (e.g. \"1234\\xde\\xad\")\n"
" -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n"
" -2 --dual dual transfer\n"
" -4 --quad quad transfer\n");
exit(1);
}
static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
{ "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' },
{ "input", 1, 0, 'i' },
{ "output", 1, 0, 'o' },
{ "loop", 0, 0, 'l' },
{ "cpha", 0, 0, 'H' },
{ "cpol", 0, 0, 'O' },
{ "lsb", 0, 0, 'L' },
{ "cs-high", 0, 0, 'C' },
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ "dual", 0, 0, '2' },
{ "verbose", 0, 0, 'v' },
{ "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v",
lopts, NULL);
if (c == -1)
break;
switch (c) {
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'i':
input_file = optarg;
break;
case 'o':
output_file = optarg;
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'v':
verbose = 1;
break;
case 'R':
mode |= SPI_READY;
break;
case 'p':
input_tx = optarg;
break;
case '2':
mode |= SPI_TX_DUAL;
break;
case '4':
mode |= SPI_TX_QUAD;
break;
default:
print_usage(argv[0]);
break;
}
}
if (mode & SPI_LOOP) {
if (mode & SPI_TX_DUAL)
mode |= SPI_RX_DUAL;
if (mode & SPI_TX_QUAD)
mode |= SPI_RX_QUAD;
}
}
static void transfer_escaped_string(int fd, char *str)
{
size_t size = strlen(str);
uint8_t *tx;
uint8_t *rx;
tx = malloc(size);
if (!tx)
pabort("can't allocate tx buffer");
rx = malloc(size);
if (!rx)
pabort("can't allocate rx buffer");
size = unescape((char *)tx, str);
transfer(fd, tx, rx, size);
free(rx);
free(tx);
}
static void transfer_file(int fd, char *filename)
{
ssize_t bytes;
struct stat sb;
int tx_fd;
uint8_t *tx;
uint8_t *rx;
if (stat(filename, &sb) == -1)
pabort("can't stat input file");
tx_fd = open(filename, O_RDONLY);
if (tx_fd < 0)
pabort("can't open input file");
tx = malloc(sb.st_size);
if (!tx)
pabort("can't allocate tx buffer");
rx = malloc(sb.st_size);
if (!rx)
pabort("can't allocate rx buffer");
bytes = read(tx_fd, tx, sb.st_size);
if (bytes != sb.st_size)
pabort("failed to read input file");
transfer(fd, tx, rx, sb.st_size);
free(rx);
free(tx);
close(tx_fd);
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
if (input_tx && input_file)
pabort("only one of -p and --input may be selected");
if (input_tx)
transfer_escaped_string(fd, input_tx);
else if (input_file)
transfer_file(fd, input_file);
else
transfer(fd, default_tx, default_rx, sizeof(default_tx));
close(fd);
return ret;
}
- 查看新增的 spidev 设备
ls /dev/spidev*
- 根据具体的 spidev 设备修改
static const char *device = "/dev/spidev0.0";这一行
例如,实际的 spidev 是 /dev/spidev1.0, 则 static const char *device = "/dev/spidev1.0";
- 在终端中,输入以下命令进行编译
gcc spidev_test.c
- 在终端中,输入以下命令进行测试
sudo ./a.out
- 检查输出结果
若输出结果和 default_tx 一致(若输出和以下一致),则表示 spi 回环测试成功
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D | ......@....�..................�.
UART
UART 简介
UART(通用异步接收器/发送器)是一种带有编程功能的微型芯片,用于控制计算机与其连接的串行设备的接口。
准备
- 一块 rock-2f
- 两根母对母杜邦线
回环测试
开启 Overlay
请参照设备树配置启用 UART 相关 Overlay, eg: "Enable UART1-M0"。
连接
如图所示,短接 Radxa ROCK 2F UART1-M0 的 PIN_7 和 PIN_40
测试
- 打开终端,在终端中输入以下命令设置串口参数
radxa@rock-2f:~$ sudo stty -F /dev/ttyS1 speed 115200 cs8 -parenb -cstopb -echo
- 在终端中,输入一下命令循环发送数据
radxa@rock-2f:~$ while true ;do echo "sss" > /dev/ttyS1; sleep 1; done;
- 新建一个终端,输入以下命令进行接收数据
radxa@rock-2f:~$ sudo cat /dev/ttyS1
收发测试
开启 Overlay
请参照设备树配置启用 UART 相关 Overlay, eg: "Enable UART1-M0" 和"Enable UART3-M0"。
连接
按照以下方式连接 UART1-M0 和 UART3-M0
| UART1-M0 | <--> | UART3-M0 |
|---|---|---|
| PIN_7 | <--> | PIN_16 |
| PIN_40 | <--> | PIN_18 |
如图所示:
测试
- 打开终端,在终端中输入以下命令设置串口参数
radxa@rock-2f:~$ sudo stty -F /dev/ttyS1 speed 115200 cs8 -parenb -cstopb -echo radxa@rock-2f:~$ sudo stty -F /dev/ttyS3 speed 115200 cs8 -parenb -cstopb -echo
- 在终端中,输入一下命令循环发送数据
UART1-M0 即 ttyS1 作为发送端
radxa@rock-2f:~$ sudo stty -F /dev/ttyS1 speed 115200 cs8 -parenb -cstopb -echo
- 新建一个终端,输入以下命令进行接收数据
UART3-M0 即 ttyS3 作为接收端
radxa@rock-2f:~$ sudo cat /dev/ttyS3
- 验证
若发送端成功发送和接收端成功接收字符 "sss",则测试成功。
- 互换发送端和接收端进行交叉验证