Skip to main content

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.

danger

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!

40-pin GPIO interface on Radxa CM4 IO Board

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.

Function7Function6Function5Function4Function3Function2Function1Pin#Pin#Function1Function2Function3Function4Function5Function6Function7
3V3
1
2
5V
PDM0_SDI1_M2I2C8_SDA_M1UART2_RX_M0GPIO1_C7_d
3
4
5V
PDM0_SDI0_M2I2C8_SCL_M1UART2_TX_M0GPIO1_C6_d
5
6
GND
SPI2_CSN0_M1I2C6_SDA_M1UART4_CTSN_M1GPIO1_C3_u
7
8
GPIO0_D4_uUART0_TX_M0_DEBUG
GND
9
10
GPIO0_D5_uUART0_RX_M0_DEBUG
UART2_RTSN_M0SPI2_MOSI_M1UART4_TX_M1GPIO1_C4_d
11
12
GPIO1_D1_dUART10_RX_M1I3C0_SDA_PU_M1SAI2_SCLK_M0
PWM1_CH0_M2GPIO2_C0_d
13
14
GND
UART2_CTSN_M0SPI2_MISO_M1UART4_RX_M1GPIO1_C5_d
15
16
GPIO2_B6_dUART7_TX_M0I2C8_SCL_M2
3V3
17
18
GPIO2_B7_dUART7_RX_M0I2C8_SDA_M2
SAI3_LRCK_M1PWM1_CH1_M1SPI1_MOSI_M0I2C9_SCL_M1GPIO1_B5_d
19
20
GND
SAI3_SDO_M1SPI1_MISO_M0UART3_CTSN_M2GPIO1_B6_d
21
22
GPIO2_D7_dPWM2_CH7_M2
SAI3_SCLK_M1PWM1_CH0_M1SPI1_CLK_M0I2C9_SDA_M1GPIO1_B4_d
23
24
GPIO1_B7_dSPI1_CSN0_M0SAI3_SDI_M1UART3_RTSN_M2
GND
25
26
GPIO1_C0_dUART3_TX_M2SPI1_CSN1_M0PWM0_CH0_M1PDM0_SDI2_M2
CAN1_RX_M1SAI4_SCLK_M2PWM2_CH3_M1I2C6_SDA_M3GPIO4_C7_d
27
28
GPIO4_C6_dI2C6_SCL_M3PWM2_CH2_M1SAI4_SDI_M2CAN1_TX_M1
CAN1_TX_M3GPIO3_A2_d
29
30
GND
PDM0_CLK0_M2SAI3_MCLK_M1UART3_RX_M2GPIO1_C1_d
31
32
GPIO1_D5_dUART10_CTSN_M1I2C5_SDA_M1SPI2_CLK_M1PDM0_CLK1_M2
UART2_RTSN_M0PWM1_CH2_M1SPI2_CSN1_M1I2C6_SCL_M1UART4_RTSN_M1GPIO1_C2_u
33
34
GND
SAI2_LRCK_M0PWM1_CH3_M1I3C0_SCL_M1GPIO1_D2_d
35
36
GPIO1_D4_dUART10_RTSN_M1I2C5_SCL_M1SAI2_MCLK_M0PDM0_SDI3_M2
CAN1_RX_M3GPIO3_A3_d
37
38
GPIO1_D3_dI3C0_SDA_M1PWM1_CH4_M1SAI2_SDI_M0
GND
39
40
GPIO1_D0_dUART10_TX_M1SAI2_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.

radxa@device$
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.

radxa@device$
# 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.

tip

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

  1. 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.

tip

For more information about the rsetup tool, refer to the Rsetup Usage guide.

  1. Set UART Permissions

The device node for UART4-M1 is /dev/ttyS4. Set the permissions to ensure the current user can access it:

radxa@device$
sudo chmod 777 /dev/ttyS4
  1. Configure UART Parameters

Set the UART communication parameters with the following command:

radxa@device$
sudo stty -F /dev/ttyS4 115200 cs8 -parenb -cstopb -echo
  • 115200: Baud rate
  • cs8: 8 data bits
  • -parenb: No parity bit
  • -cstopb: 1 stop bit
  • -echo: Disable echo
  1. Send Data via UART

Open a terminal and enter the following command to continuously send test messages:

radxa@device$
while true; do echo "UART4 test" > /dev/ttyS4; sleep 1; done
  1. Receive UART Data

Open another terminal and enter the following command to display received data:

radxa@device$
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 CM4OLED Screen
PIN_1 (3.3V)VCC
PIN_3 (I2C8_SDA_M1)SDA
PIN_5 (I2C8_SCL_M1)SCL
PIN_9 (GND)GND

I2C Testing

  1. 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.

  1. 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:

radxa@device$
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:

radxa@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):

radxa@device$
sudo i2cdetect -y -r *
# Example
sudo i2cdetect -y -r 8

Terminal output example (OLED I2C address is 0x3c):

radxa@device$
     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: -- -- -- -- -- -- -- --
  1. 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:

radxa@device$
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.

tip

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

  1. 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.

  1. Query SPI Bus Devices

Use the ls /dev/spidev* command to view SPI bus device information:

radxa@device$
ls /dev/spidev\*

Terminal output example:

/dev/spidev1.0
  1. 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:

radxa@device$

sudo apt update
sudo apt install build-essential

  • Compile the Code

Open a terminal and enter the following command to compile the code:

radxa@device$

gcc -o spidev_test spidev_test.c

  • Run the Code

Open a terminal and enter the following command to run the code:

radxa@device$

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 | ......@....�..................�.