Skip to main content

接口定义

整机接口定义

LBA3588S提供了丰富的接口,具体如下图

丝印设备节点备注
USB1Type-A USB3.0 host
USB2Type-A USB3.0 host
USB3Type-A USB3.0 host
PWR LED电源灯
4G LED4G灯 4G/5G 拨号
SYS LEDwork1系统灯
STA LEDwork2STA灯
RS485/dev/ttyS9串口,默认波特率9600
UART1/dev/ttyS4串口,默认波特率9600
UART2/dev/ttyS6串口,默认波特率9600
RS232_1/dev/ttysWK0串口RS232,默认波特率9600
RS232_2/dev/ttysWK1串口RS232,默认波特率9600
RS232_3/dev/ttysWK2串口RS232,默认波特率9600
RS232_4/dev/ttysWK3串口RS232,默认波特率9600
HDMIcard0-HDMI-A-1HDMI输出,最高支持4K@60fps
Type-C可转接USB和DP信号
MIC输入声音,录制音频文件
LINE播放音频文件
ETHeth0千兆网卡
WIFIwlan02.4/5GHz

UART 使用

串口是一种常见的通信接口,用于与外部设备进行串行通信。LBA3588S提供了多个串口,分别对应不同的设备节点。在使用串口之前,需要确保串口连接正确,以及波特率和其他参数设置一致。

RS485设备文件为/dev/ttyS9。在开发板设备上运行下列命令:

发送字符串到主机

  • Cmd
  • C
echo "neardi RS485 test..." > /dev/ttyS9

create serial_send.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include <stdlib.h>

void usage(const char *prog_name) {
printf("Usage: %s <port> <message> [baudrate] [timeout]\n", prog_name);
printf(" <port> - The serial port to use (e.g., /dev/ttyS0)\n");
printf(" <message> - The message to send\n");
printf(" [baudrate] - The baud rate (optional, default is 9600)\n");
printf(" [timeout] - The timeout in seconds (optional, default is 1)\n");
}

int main(int argc, char *argv[]) {
if (argc < 3) {
usage(argv[0]);
return 1;
}

const char *port = argv[1];
const char *message = argv[2];
int baudrate = (argc > 3) ? atoi(argv[3]) : 9600;
int timeout = (argc > 4) ? atoi(argv[4]) : 1;

int fd = open(port, O_WRONLY | O_NOCTTY | O_SYNC);
if (fd == -1) {
perror("Unable to open serial port");
return 1;
}

// Set serial port configuration
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
perror("Error getting serial port attributes");
close(fd);
return 1;
}

// Set baud rate
cfsetospeed(&tty, baudrate);
cfsetispeed(&tty, baudrate);

// Set serial port mode
tty.c_cflag &= ~PARENB; // No checksum
tty.c_cflag &= ~CSTOPB; // 1 stop bit
tty.c_cflag &= ~CSIZE; // Clear character bit settings
tty.c_cflag |= CS8; // 8 data bits
tty.c_cflag |= CREAD | CLOCAL; // Start the receiver, ignore control lines

// Set timeout
tty.c_cc[VTIME] = timeout; // Read operation timeout (10ms unit)
tty.c_cc[VMIN] = 0; // Read without waiting for characters

// Apply serial port settings
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("Error setting serial port attributes");
close(fd);
return 1;
}

// Send data
write(fd, message, strlen(message));
printf("Message sent: %s\n", message);

// Close serial port
close(fd);
return 0;
}
gcc -o serial_send serial_send.c
./serial_send /dev/ttyS9 "neardi RS485 test ..." 9600 1

主机中的串口终端即可接收到字符串 “neardi RS485 test…” 开发板接收数据:

接收主机发送的字符串

  • Cmd
  • C
cat /dev/ttyS9

create serial_reader.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>

#define DEFAULT_SERIAL_PORT "/dev/ttyS0"
#define DEFAULT_BAUD_RATE 115200

// Map baud rate string to corresponding baud rate constant
speed_t get_baud_rate(int baud) {
switch (baud) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 921600:
return B921600;
default:
return B115200; // Default baud rate 115200
}
}

// Print help information
void print_usage() {
printf("Usage: serial_reader -p <port> -b <baud_rate>\n");
printf(" -p <port> Serial port device (default: /dev/ttyS9)\n");
printf(" -b <baud_rate> Baud rate (default: 115200)\n");
}

int main(int argc, char *argv[]) {
int baud_rate = DEFAULT_BAUD_RATE;
const char *serial_port = DEFAULT_SERIAL_PORT;

// Parse command line arguments
int opt;
while ((opt = getopt(argc, argv, "p:b:h")) != -1) {
switch (opt) {
case 'p':
serial_port = optarg;
break;
case 'b':
baud_rate = atoi(optarg);
if (baud_rate <= 0) {
fprintf(stderr, "Invalid baud rate: %s\n", optarg);
print_usage();
return 1;
}
break;
case 'h':
default:
print_usage();
return 0;
}
}

// Open serial device
int serial_fd = open(serial_port, O_RDONLY | O_NOCTTY);
if (serial_fd == -1) {
perror("Failed to open the serial port");
return 1;
}

// Set serial port parameters
struct termios tty;
if (tcgetattr(serial_fd, &tty) != 0) {
perror("Failed to get serial port attributes");
close(serial_fd);
return 1;
}

// Configure baud rate
speed_t baud = get_baud_rate(baud_rate);
cfsetospeed(&tty, baud); // Set output baud rate
cfsetispeed(&tty, baud); // Set input baud rate

// Configure serial port
tty.c_cflag &= ~PARENB; // Disable parity checking
tty.c_cflag &= ~CSTOPB; // 1 stop bit
tty.c_cflag &= ~CSIZE; // Clear data bit mask
tty.c_cflag |= CS8; // 8 data bits
tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control
tty.c_cflag |= CREAD | CLOCAL; // Enable receive and local connections
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable software flow control
tty.c_iflag &= ~ICANON; // Disable canonical mode
tty.c_iflag &= ~ECHO; // Disable echo
tty.c_iflag &= ~ECHOE; // Disable echo input
tty.c_iflag &= ~ISIG; // Disable signal characters
tty.c_oflag &= ~OPOST; // Disable output processing
tty.c_oflag &= ~ONLCR; // Disable newline conversion

// Application serial port configuration
if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
perror("Failed to set serial port attributes");
close(serial_fd);
return 1;
}

// Loop to read serial port data and output
char read_buffer[256];
while (1) {
int n = read(serial_fd, read_buffer, sizeof(read_buffer) - 1);
if (n < 0) {
perror("Failed to read from the serial port");
close(serial_fd);
return 1;
} else if (n == 0) {
continue; // No data to read, continue looping
}
read_buffer[n] = '\0'; // Make sure the string ends
printf("%s", read_buffer); // Output the read data
}

close(serial_fd);
return 0;
}
gcc -o serial_reader serial_reader.c
./serial_reader -p /dev/ttyS9 -b 9600

同样,UART1和UART2设备文件分别是/dev/ttyS4/dev/ttyS6

RS232 使用

RS232使用方法与RS485、UART1和UART2类似,只需替换设备文件即可。

HDMI/DP 说明

xrandx命令可以查看当前HDMI连接:

neardi@3588:~$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384
HDMI-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
1920x1080 60.00*+ 60.00 50.00 30.00 24.00
4096x2160 24.00
3840x2160 30.00 25.00 24.00
1920x1080i 60.00 50.00
1280x720 60.00 60.00 50.00 50.00 30.00 24.00
720x576 50.00 50.00
720x480 59.94 59.94 59.94
DP-1 disconnected (normal left inverted right x axis y axis)

完整节点:

HDMI1:/sys/devices/platform/display-subsystem/drm/card0/card0-HDMI-A-1/
DP:/sys/devices/platform/display-subsystem/drm/card0/card0-DP-2/

设置分辨率

ETH 说明

可以通过调试串口、ssh或者adb来查看IP地址,例如:

neardi@3588:~$ ifconfig -a
enP2p33s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.65 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::7df7:e74d:497e:345d prefixlen 64 scopeid 0x20<link>
ether 62:ea:fb:ca:95:e7 txqueuelen 1000 (Ethernet)
RX packets 2548 bytes 210938 (210.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 338 bytes 46899 (46.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 140 base 0xd000

Wi-Fi 说明

通过如下命令查看当前Wi-Fi型号:

cat /sys/bus/sdio/devices/mmc2\:0001\:1/vendor
cat /sys/bus/sdio/devices/mmc2\:0001\:1/device
  • 0x02d0:0xaae8:AP6275S.
  • 0x024c:0xb852:RTL8852.
  • 0x024c:0xd723:RTL8723DS.
  • 0x024c:0xc821:RTL8821CS.
  • 0x1ffe:0x6316:FD7352S

Connect Wi-Fi:

  • Cmd

  • C

  • Search Wi-Fi:

sudo nmcli device wifi rescan
  • Show all Wi-Fi:
nmcli dev wifi list
  • Connect Wi-Fi:
sudo nmcli device wifi connect neardi_5G password neardi_pwd

• neardi_5G 是WiFi 网络(SSID) 的名称。

• neardi_pwd 是连接到该WiFi 网络所需的密码。

• sudo 用于确保nmcli 具有管理网络连接所需的权限,因为在某些系统上连接到WiFi 网络可能需要管理权限。

create connect_wifi.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void connect_to_wifi(const char *ssid, const char *password) {
char command[256];

// Create the WPA configuration file without the -e option
snprintf(command, sizeof(command), "echo 'network={\\n ssid=\"%s\"\\n psk=\"%s\"\\n}' | sudo tee /etc/wpa_supplicant/wpa_supplicant.conf", ssid, password);
if (system(command) != 0) {
perror("Failed to create wpa_supplicant.conf");
return;
}

// Run wpa_supplicant
if (system("sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf") != 0) {
perror("Failed to start wpa_supplicant");
return;
}

// Obtain an IP address
if (system("sudo dhclient wlan0") != 0) {
perror("Failed to obtain an IP address");
}
}

int main() {
const char *ssid = "neardi_5G";
const char *password = "neardi_pwd";

connect_to_wifi(ssid, password);
return 0;
}
gcc connect_wifi.c -o connect_wifi
sudo ./connect_wifi

启动热点

LED 说明

完整节点:

SYS LED:cat /sys/devices/platform/leds/leds/work1/brightness
STA LED:cat /sys/devices/platform/leds/leds/work2/brightness

MIC 使用

使用以下命令可以录制音频文件,支持wav、mp3等格式。

录制双声道的16位小端格式的音频,采样率为48000Hz,然后保存为001.wav文件。

  • Cmd
  • C
  • Python
arecord -Dhw:0,0 -r48000 -f S16_LE -c2 > 001.wav

• -Dhw:0,0 指定了录音设备,0,0 是card 0 device 0,也就是第一个声卡的第一个设备。

• -r48000 指定了采样率,单位是Hz,48000表示每秒采样48000次。

• -f S16_LE 指定了采样格式,S16_LE表示有符号的16位小端格式,也就是每个采样点占用2个字节,低位在前,高位在后。

• -c2 指定了声道数,2表示双声道,也就是立体声。

• > 001.wav 指定了输出文件,>表示重定向标准输出到文件,001.wav表示文件名,wav表示文件格式。

create audio_record.c

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

#define SAMPLE_RATE 44100 // Replace SAMPLE_RATE with a local variable
#define CHANNELS 2 // Replace CHANNELS with a local variable

int main(int argc, char *argv[]) {
const char *device = "hw:0,0"; // Set the audio device
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
unsigned int sample_rate = SAMPLE_RATE; // Use a modifiable local variable
int channels = CHANNELS; // Use a modifiable local variable
int pcm, dir;
snd_pcm_uframes_t frames = 32;
FILE *file = fopen("001.wav", "wb");
if (!file) {
perror("Unable to create audio file");
return 1;
}

// Open PCM device
if ((pcm = snd_pcm_open(&pcm_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf(stderr, "Unable to open PCM device %s: %s\n", device, snd_strerror(pcm));
fclose(file);
return 1;
}

// Set hardware parameters
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm_handle, params, channels); // Use the variable channels
snd_pcm_hw_params_set_rate_near(pcm_handle, params, &sample_rate, &dir); // Use the variable sample_rate

// Apply parameters
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0) {
fprintf(stderr, "Unable to set hardware parameters: %s\n", snd_strerror(pcm));
snd_pcm_close(pcm_handle);
fclose(file);
return 1;
}

// Get buffer size
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
int buffer_size = frames * channels * 2; // 2 bytes per channel
char *buffer = (char *)malloc(buffer_size);

// Write WAV file header
fwrite("RIFF", 1, 4, file);
fwrite("----", 1, 4, file); // Placeholder
fwrite("WAVE", 1, 4, file);
fwrite("fmt ", 1, 4, file);
int subchunk1_size = 16;
short audio_format = 1;
fwrite(&subchunk1_size, 4, 1, file);
fwrite(&audio_format, 2, 1, file);
fwrite(&channels, 2, 1, file); // Use the variable channels
fwrite(&sample_rate, 4, 1, file); // Use the variable sample_rate
int byte_rate = sample_rate * channels * 2;
fwrite(&byte_rate, 4, 1, file);
short block_align = channels * 2;
fwrite(&block_align, 2, 1, file);
short bits_per_sample = 16;
fwrite(&bits_per_sample, 2, 1, file);

// Write WAV data header
fwrite("data", 1, 4, file);
fwrite("----", 1, 4, file); // Placeholder

printf("Starting recording...\n");

// Start recording
int total_data_size = 0;
while (1) {
pcm = snd_pcm_readi(pcm_handle, buffer, frames);
if (pcm == -EPIPE) {
snd_pcm_prepare(pcm_handle);
} else if (pcm < 0) {
fprintf(stderr, "Recording failed: %s\n", snd_strerror(pcm));
break;
}
fwrite(buffer, 1, buffer_size, file);
total_data_size += buffer_size;
}

// Update WAV file size
fseek(file, 4, SEEK_SET);
int file_size = total_data_size + 36;
fwrite(&file_size, 4, 1, file);
fseek(file, 40, SEEK_SET);
fwrite(&total_data_size, 4, 1, file);

// Clean up resources
free(buffer);
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
fclose(file);

printf("Recording complete\n");
return 0;
}
gcc audio_record.c -o audio_record -lasound
./audio_record

Install the PyAudio library:

sudo apt update
sudo apt install python3-pip
sudo apt install portaudio19-dev
pip3 install pyaudio

create audio_record.py

import wave
import pyaudio

# Audio format parameters
FORMAT = pyaudio.paInt16 # 16-bit PCM
CHANNELS = 2
RATE = 48000 # Sample rate
CHUNK = 4096 # Buffer size

# Create a PyAudio object
p = pyaudio.PyAudio()

# Open an audio stream
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)

# Open a WAV file for writing
wf = wave.open('001.wav', 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)

print("Recording...")

# Record audio data
try:
while True:
data = stream.read(CHUNK)
wf.writeframes(data)
except KeyboardInterrupt:
print("Recording stopped.")

# Clean up
print("Recording complete. Saved as 001.wav")
stream.stop_stream()
stream.close()
p.terminate()
wf.close()
python audio_record.py

LINE 使用

使用第一个声卡的第一个设备播放001.wav文件。

  • Cmd
  • C
  • Python
aplay -D hw:0,0 001.wav

• -D hw:0,0 指定了播放设备,hw:0,0 是card 0 device 0,也就是第一个声卡的第一个设备。

• 001.wav 指定了音频文件,wav表示文件格式,001表示文件名。

Install the ALSA library and its development headers:

sudo apt update
sudo apt install libasound2-dev

create audio_play.c

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

int main(int argc, char *argv[]) {
const char *device = "hw:0,0"; // Set audio device
const char *filename = "001.wav"; // Audio file path
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
unsigned int sample_rate = 44100; // Sample rate
int pcm, dir;
snd_pcm_uframes_t frames;
FILE *file;
char *buffer;
int buffer_size;

// Open audio file
file = fopen(filename, "rb");
if (!file) {
perror("Unable to open audio file");
return 1;
}

// Open PCM device
if ((pcm = snd_pcm_open(&pcm_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf(stderr, "Unable to open PCM device %s: %s\n", device, snd_strerror(pcm));
fclose(file);
return 1;
}

// Set hardware parameters
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm_handle, params, 2);
snd_pcm_hw_params_set_rate_near(pcm_handle, params, &sample_rate, &dir);

// Apply parameters
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0) {
fprintf(stderr, "Unable to set hardware parameters: %s\n", snd_strerror(pcm));
snd_pcm_close(pcm_handle);
fclose(file);
return 1;
}

// Get frame size and buffer size
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
buffer_size = frames * 4; // 2 channels, each sample is 2 bytes
buffer = (char *) malloc(buffer_size);

// Play audio
while (fread(buffer, 1, buffer_size, file) > 0) {
if ((pcm = snd_pcm_writei(pcm_handle, buffer, frames)) == -EPIPE) {
snd_pcm_prepare(pcm_handle);
} else if (pcm < 0) {
fprintf(stderr, "Playback failed: %s\n", snd_strerror(pcm));
}
}

// Cleanup
free(buffer);
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
fclose(file);

printf("Playback completed\n");
return 0;
}
gcc audio_play.c -o audio_play -lasound
./audio_play

Install the PyAudio and wave libraries:

sudo apt update
sudo apt install python3-pyaudio

create audio_play.py

import pyaudio
import wave

def play_audio(filename):
# Open WAV audio file
with wave.open(filename, 'rb') as wf:
# Initialize PyAudio
p = pyaudio.PyAudio()

# Configure audio stream
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)

# Read and play audio data
data = wf.readframes(1024)
while data:
stream.write(data)
data = wf.readframes(1024)

# Stop and close audio stream
stream.stop_stream()
stream.close()

# Terminate PyAudio
p.terminate()
print("Playback completed")

# Play file
play_audio('001.wav')
python3 audio_play.py