UART Terminal for orange pi
2025-10-11
"screen" command not work, may be the baurate too high, orange pi is using 1.5M. so use this command
picocom -b 1500000 /dev/tty.usbserial-A50285BI


The maximum speed to toggle a pin by python running inside cm4 is just 150khz

Determine the Linux GPIO Number for GPIO3_D1
The Orange Pi CM4 uses a 40-pin header, and GPIO3_D1 corresponds to a specific Linux GPIO number. The RK3566 GPIO numbering follows the formula:
GPIO_number = (bank_number * 32) + (subgroup_letter - 'A') * 8 + pin_number
- GPIO3_D1:
- Bank: GPIO3 (bank number 3)
- Subgroup: D (D - A = 3)
- Pin: 1
- Calculation: (3 * 32) + (3 * 8) + 1 = 96 + 24 + 1 = 121
So, GPIO3_D1 is Linux GPIO 121. According to the Orange Pi CM4 pinout, GPIO3_D1 is physical pin 18 on the 40-pin header.
import os
import sys
import time
import signal
# Configuration
GPIO_NUMBER = 121 # GPIO3_D1 (physical pin 18)
LOOP_COUNT = 10000000 # Toggle 10 million times (~5-10s)
BASE_PATH = '/sys/class/gpio'
# Global flag for graceful exit
running = True
def signal_handler(sig, frame):
global running
print('\nStopping toggle...')
running = False
signal.signal(signal.SIGINT, signal_handler)
def main():
# Check if root
if os.geteuid() != 0:
print("Error: Run as root (sudo).", file=sys.stderr)
sys.exit(1)
gpio_path = f'{BASE_PATH}/gpio{GPIO_NUMBER}'
# Export GPIO
if not os.path.exists(gpio_path):
try:
with open(f'{BASE_PATH}/export', 'w') as f:
f.write(str(GPIO_NUMBER))
time.sleep(0.1) # Allow setup
except IOError as e:
print(f"Error exporting GPIO {GPIO_NUMBER}: {e}", file=sys.stderr)
sys.exit(1)
# Set as output
try:
with open(f'{gpio_path}/direction', 'w') as f:
f.write('out')
except IOError as e:
print(f"Error setting direction: {e}", file=sys.stderr)
sys.exit(1)
# Open value file for fast I/O in binary mode
try:
value_file = open(f'{gpio_path}/value', 'wb', buffering=0)
except IOError as e:
print(f"Error opening value file: {e}", file=sys.stderr)
sys.exit(1)
print(f"Toggling GPIO {GPIO_NUMBER} (GPIO3_D1, physical pin 18)...")
print(f"Press Ctrl+C to stop.")
start_time = time.perf_counter()
count = 0
while running and (LOOP_COUNT == 0 or count < LOOP_COUNT):
value_file.write(b'1') # Write bytes
value_file.write(b'0') # Write bytes
value_file.flush() # Ensure write
count += 1
end_time = time.perf_counter()
value_file.close()
# Cleanup
try:
with open(f'{BASE_PATH}/unexport', 'w') as f:
f.write(str(GPIO_NUMBER))
except IOError:
pass
duration = end_time - start_time
if duration > 0:
freq_hz = (count * 2) / duration
print(f"\nCompleted {count} toggles in {duration:.3f}s ({freq_hz:.0f} Hz).")
if __name__ == '__main__':
main()
If using C, it reaches 352khz, 2 times faster
This command check the memory base address of GPIO
dtc -I fs /sys/firmware/devicetree/base | grep -i gpio3
Compile:
sudo apt update
sudo apt install build-essential
cat /sys/kernel/debug/gpio
gcc -o toggle_gpio3_d1 toggle_gpio3_d1.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#define SYSFS_GPIO_PATH "/sys/class/gpio"
#define GPIO_NUM 121 // GPIO3_D1
volatile sig_atomic_t running = 1;
void signal_handler(int sig) {
running = 0;
}
int main() {
int fd_export, fd_direction, fd_value;
char path[64];
// Check if root
if (geteuid() != 0) {
fprintf(stderr, "Error: Run as root (sudo).\n");
return 1;
}
// Export GPIO
snprintf(path, sizeof(path), "%s/export", SYSFS_GPIO_PATH);
fd_export = open(path, O_WRONLY);
if (fd_export < 0) {
perror("Error exporting GPIO");
return 1;
}
dprintf(fd_export, "%d", GPIO_NUM);
close(fd_export);
usleep(100000); // Wait for export
// Set as output
snprintf(path, sizeof(path), "%s/gpio%d/direction", SYSFS_GPIO_PATH, GPIO_NUM);
fd_direction = open(path, O_WRONLY);
if (fd_direction < 0) {
perror("Error setting direction");
return 1;
}
write(fd_direction, "out", 3);
close(fd_direction);
// Open value file
snprintf(path, sizeof(path), "%s/gpio%d/value", SYSFS_GPIO_PATH, GPIO_NUM);
fd_value = open(path, O_WRONLY);
if (fd_value < 0) {
perror("Error opening value file");
return 1;
}
printf("Toggling GPIO3_D1 (Linux GPIO %d) at ~500 Hz to find physical pin...\n", GPIO_NUM);
printf("Test pins 15, 16, 18 with oscilloscope. Press Ctrl+C to stop.\n");
// Slow toggle for testing
while (running) {
write(fd_value, "1", 1);
//usleep(1000); // 1ms
write(fd_value, "0", 1);
//usleep(1000); // 1ms
}
// Cleanup
close(fd_value);
snprintf(path, sizeof(path), "%s/unexport", SYSFS_GPIO_PATH);
fd_export = open(path, O_WRONLY);
if (fd_export >= 0) {
dprintf(fd_export, "%d", GPIO_NUM);
close(fd_export);
}
printf("GPIO3_D1 unexported\n");
return 0;
}
Command to toggle pin GPIO3_D1 (GPIO 121)
# Export GPIO 121
echo 121 > /sys/class/gpio/export
# Set as output
echo out > /sys/class/gpio/gpio121/direction
# Toggle manually and check with scope
echo 1 > /sys/class/gpio/gpio121/value
echo 0 > /sys/class/gpio/gpio121/value
# Cleanup
echo 121 > /sys/class/gpio/unexport