40-Pin GPIO Interface
The Radxa CM4 IO Board features an onboard 40-pin GPIO interface, providing highly flexible hardware expansion capabilities.
You can connect various sensors, actuators, communication modules, displays, and other embedded peripherals through the 40-pin GPIO interface, enabling rapid prototyping and functional verification in fields such as IoT, robotics control, industrial automation, and more.
When using the 40-pin GPIO interface, please pay attention to pin connections and peripheral wiring. Ensure all connections are correct, as improper operation may cause hardware damage!

GPIO Features
When the Radxa CM4 is installed on the Radxa CM4 IO Board, you can connect peripherals through the 40-pin GPIO interface, which supports various functions including UART, I2C, SPI, and PWM.
Function7 | Function6 | Function5 | Function4 | Function3 | Function2 | Function1 | Pin# | Pin# | Function1 | Function2 | Function3 | Function4 | Function5 | Function6 | Function7 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
3V3 | 1 | 2 | 5V | ||||||||||||
PDM0_SDI1_M2 | I2C8_SDA_M1 | UART2_RX_M0 | GPIO1_C7_d | 3 | 4 | 5V | |||||||||
PDM0_SDI0_M2 | I2C8_SCL_M1 | UART2_TX_M0 | GPIO1_C6_d | 5 | 6 | GND | |||||||||
SPI2_CSN0_M1 | I2C6_SDA_M1 | UART4_CTSN_M1 | GPIO1_C3_u | 7 | 8 | GPIO0_D4_u | UART0_TX_M0_DEBUG | ||||||||
GND | 9 | 10 | GPIO0_D5_u | UART0_RX_M0_DEBUG | |||||||||||
UART2_RTSN_M0 | SPI2_MOSI_M1 | UART4_TX_M1 | GPIO1_C4_d | 11 | 12 | GPIO1_D1_d | UART10_RX_M1 | I3C0_SDA_PU_M1 | SAI2_SCLK_M0 | ||||||
PWM1_CH0_M2 | GPIO2_C0_d | 13 | 14 | GND | |||||||||||
UART2_CTSN_M0 | SPI2_MISO_M1 | UART4_RX_M1 | GPIO1_C5_d | 15 | 16 | GPIO2_B6_d | UART7_TX_M0 | I2C8_SCL_M2 | |||||||
3V3 | 17 | 18 | GPIO2_B7_d | UART7_RX_M0 | I2C8_SDA_M2 | ||||||||||
SAI3_LRCK_M1 | PWM1_CH1_M1 | SPI1_MOSI_M0 | I2C9_SCL_M1 | GPIO1_B5_d | 19 | 20 | GND | ||||||||
SAI3_SDO_M1 | SPI1_MISO_M0 | UART3_CTSN_M2 | GPIO1_B6_d | 21 | 22 | GPIO2_D7_d | PWM2_CH7_M2 | ||||||||
SAI3_SCLK_M1 | PWM1_CH0_M1 | SPI1_CLK_M0 | I2C9_SDA_M1 | GPIO1_B4_d | 23 | 24 | GPIO1_B7_d | SPI1_CSN0_M0 | SAI3_SDI_M1 | UART3_RTSN_M2 | |||||
GND | 25 | 26 | GPIO1_C0_d | UART3_TX_M2 | SPI1_CSN1_M0 | PWM0_CH0_M1 | PDM0_SDI2_M2 | ||||||||
CAN1_RX_M1 | SAI4_SCLK_M2 | PWM2_CH3_M1 | I2C6_SDA_M3 | GPIO4_C7_d | 27 | 28 | GPIO4_C6_d | I2C6_SCL_M3 | PWM2_CH2_M1 | SAI4_SDI_M2 | CAN1_TX_M1 | ||||
CAN1_TX_M3 | GPIO3_A2_d | 29 | 30 | GND | |||||||||||
PDM0_CLK0_M2 | SAI3_MCLK_M1 | UART3_RX_M2 | GPIO1_C1_d | 31 | 32 | GPIO1_D5_d | UART10_CTSN_M1 | I2C5_SDA_M1 | SPI2_CLK_M1 | PDM0_CLK1_M2 | |||||
UART2_RTSN_M0 | PWM1_CH2_M1 | SPI2_CSN1_M1 | I2C6_SCL_M1 | UART4_RTSN_M1 | GPIO1_C2_u | 33 | 34 | GND | |||||||
SAI2_LRCK_M0 | PWM1_CH3_M1 | I3C0_SCL_M1 | GPIO1_D2_d | 35 | 36 | GPIO1_D4_d | UART10_RTSN_M1 | I2C5_SCL_M1 | SAI2_MCLK_M0 | PDM0_SDI3_M2 | |||||
CAN1_RX_M3 | GPIO3_A3_d | 37 | 38 | GPIO1_D3_d | I3C0_SDA_M1 | PWM1_CH4_M1 | SAI2_SDI_M0 | ||||||||
GND | 39 | 40 | GPIO1_D0_d | UART10_TX_M1 | SAI2_SDO_M0 |
GPIO Usage
This section demonstrates common GPIO usage through the onboard 40-pin GPIO interface.
GPIO Input
Hardware Requirements
- Board: Radxa CM4
- 1x Female-to-female jumper wire
Hardware Connection
For GPIO input testing using GPIO_Pin_3, you can connect a female-to-female jumper wire to PIN_3.
Reading Test
Use the gpiofind
command to locate the device node corresponding to the GPIO pin, then use the gpioget
command to read the pin state.
gpioget $(gpiofind PIN_3)
You can connect the jumper wire from PIN_3 to either GND or 3.3V, then read the pin state.
Terminal output example (when connected to GND, output 0 indicates low level, 1 indicates high level):
0
GPIO Output
Hardware Requirements
- Board: Radxa CM4
- 1x Female-to-female jumper wire
Hardware Connection
For GPIO output testing using GPIO_Pin_3, you can connect a female-to-female jumper wire to PIN_3.
Output Test
Use the gpiofind
command to locate the device node corresponding to the GPIO pin, then use the gpioset
command to set the pin state.
# Set output high
gpioset -m signal $(gpiofind PIN_3)=1
# Set output low
gpioset -m signal $(gpiofind PIN_3)=0
-m signal
: Set pin to signal mode$(gpiofind PIN_3)
: Find the device node for the GPIO pin=1
: Set pin state to high
You can verify the pin state by measuring the voltage with a multimeter or by connecting the pin to another controllable pin for reading.
UART Usage
UART (Universal Asynchronous Receiver/Transmitter) is a widely used serial communication protocol for asynchronous serial data transmission between embedded systems, computers, and peripherals.
Hardware Requirements
- Board: Radxa CM4
- 1x Female-to-female jumper wire
Hardware Connection
For UART4-M1 loopback testing, connect PIN_11 (UART4_TX_M1) to PIN_15 (UART4_RX_M1) using a female-to-female jumper wire.
For the UART loopback test, we only need to connect the TX and RX pins.
When connecting to other UART modules, you'll also need to connect the GND pin to ensure a common ground between devices.
Loopback Test
- Enable UART4-M1
Use the rsetup
tool to enable UART4-M1: Overlays
--> Manage Overlays
--> Check Enable UART4-M1
.
After enabling UART4-M1, a system reboot is required for the changes to take effect.
For more information about the rsetup
tool, refer to the Rsetup Usage guide.
- Set UART Permissions
The device node for UART4-M1
is /dev/ttyS4
. Set the permissions to ensure the current user can access it:
sudo chmod 777 /dev/ttyS4
- Configure UART Parameters
Set the UART communication parameters with the following command:
sudo stty -F /dev/ttyS4 115200 cs8 -parenb -cstopb -echo
115200
: Baud ratecs8
: 8 data bits-parenb
: No parity bit-cstopb
: 1 stop bit-echo
: Disable echo
- Send Data via UART
Open a terminal and enter the following command to continuously send test messages:
while true; do echo "UART4 test" > /dev/ttyS4; sleep 1; done
- Receive UART Data
Open another terminal and enter the following command to display received data:
cat /dev/ttyS4
If the loopback test is successful, you should see the message UART4 test
appear every second in the terminal receiving the UART data.
I2C Usage
I2C is a widely used synchronous serial communication protocol developed by Philips (now NXP), primarily used for short-distance inter-chip communication.
Hardware Requirements
- Board: Radxa CM4
- 4x Female-to-female jumper wires
- OLED screen (I2C communication)
Hardware Connection
Connect the Radxa CM4 to the OLED screen using 4 female-to-female jumper wires:
Radxa CM4 | OLED Screen |
---|---|
PIN_1 (3.3V) | VCC |
PIN_3 (I2C8_SDA_M1) | SDA |
PIN_5 (I2C8_SCL_M1) | SCL |
PIN_9 (GND) | GND |
I2C Testing
- Enable I2C8-M1
Use the rsetup
tool to enable I2C8-M1: Overlays
--> Manage Overlays
--> Check Enable I2C8-M1
.
After enabling I2C8-M1, a system reboot is required for the changes to take effect.
- Query I2C Bus Devices
Use the i2cdetect
command to query I2C bus device information.
- Install Dependencies
Open a terminal and install Python3-periphery and i2c-tools:
sudo apt update
sudo apt install python3-periphery i2c-tools
- View I2C Buses
Use the i2cdetect
command to view all I2C buses on the device:
sudo i2cdetect -l
Terminal output example:
i2c-1 i2c rk3x-i2c I2C adapter
i2c-2 i2c rk3x-i2c I2C adapter
i2c-3 i2c rk3x-i2c I2C adapter
i2c-6 i2c rk3x-i2c I2C adapter
i2c-8 i2c rk3x-i2c I2C adapter
i2c-10 i2c ddc I2C adapter
- View I2C Bus Devices
Use the i2cdetect
command to view devices on a specific I2C bus. Replace *
with the bus number (e.g., 8 for i2c-8
):
sudo i2cdetect -y -r *
# Example
sudo i2cdetect -y -r 8
Terminal output example (OLED I2C address is 0x3c):
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
- I2C Communication Test
- Python Script
Create a new Python script named oled_test.py
with the following content. Modify I2C_ADDR
and I2C_BUS
according to your setup.
oled_test.py
from periphery import I2C
import time
I2C_ADDR = 0x3c
I2C_BUS = "/dev/i2c-8"
i2c = I2C(I2C_BUS)
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()
- Run the Script
Open a terminal and run the script with:
python3 oled_test.py
If everything works correctly, you should see Hello Radxa
displayed on the OLED screen.
SPI Usage
SPI (Serial Peripheral Interface) is a high-speed, full-duplex, synchronous serial communication protocol developed by Motorola (now NXP). It's primarily used for short-distance inter-chip communication, commonly found in data transfer between microcontrollers and devices such as sensors, memory (like Flash), displays, etc.
Hardware Requirements
- Board: Radxa CM4
- 1x Female-to-female jumper wire
Hardware Connection
For SPI1-M0 loopback testing, connect PIN_19 (SPI1_MOSI_M0) to PIN_21 (SPI1_MISO_M0) using a female-to-female jumper wire.
For the SPI loopback test, we only need to connect the MOSI and MISO pins.
When connecting to other SPI modules, you'll also need to connect the GND pin to ensure a common ground between devices.
Loopback Test
- Enable SPI1-M0
Use the rsetup
tool to enable SPI1-M0: Overlays
--> Manage Overlays
--> Check Enable spidev on SPI1-M0 over CS0
.
After enabling SPI1-M0, a system reboot is required for the changes to take effect.
- Query SPI Bus Devices
Use the ls /dev/spidev*
command to view SPI bus device information:
ls /dev/spidev\*
Terminal output example:
/dev/spidev1.0
- SPI Communication Test
- C Code
Create a new C file named spidev_test.c
with the following content. Modify static const char *device = "/dev/spidev1.0";
to match your SPI bus device node.
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/spidev1.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;
}
- Compilation Tools
Open a terminal and enter the following commands to install the build tools:
sudo apt update
sudo apt install build-essential
- Compile the Code
Open a terminal and enter the following command to compile the code:
gcc -o spidev_test spidev_test.c
- Run the Code
Open a terminal and enter the following command to run the code:
sudo ./spidev_test
If the loopback test is successful, you should see the following output in the terminal:
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 | ......@....�..................�.