1. 案例背景与开发板介绍
GM-3568JHF是一款由ShiMetaPi研发的ARM+FPGA异构开发板,搭载Rockchip RK3568处理器和Xilinx Artix-7系列FPGA。这款开发板特别适合需要高性能计算与实时控制相结合的嵌入式应用场景,如工业自动化、机器视觉和边缘计算等。
开发板提供了丰富的通信接口,其中UART串口是最基础也最常用的外设之一。在实际项目中,UART常用于:
- 与传感器模块通信
- 设备调试信息输出
- 与其他微控制器进行数据交换
- 工业现场总线通信(如Modbus RTU)
2. 硬件连接详解
2.1 接口定义与物理连接
TTL UART4接口采用标准的4针连接器,引脚定义如下:
| 引脚编号 | 信号名称 | 说明 | 连接线颜色 |
|---|---|---|---|
| 1 | VCC | 3.3V电源输出 | 红色 |
| 2 | GND | 地线 | 黑色 |
| 3 | TXD | 数据发送线 | 绿色 |
| 4 | RXD | 数据接收线 | 白色 |
注意:连接USB转TTL模块时,务必遵循"交叉连接"原则:
- 开发板TXD → 模块RXD
- 开发板RXD → 模块TXD
- VCC可不连接,避免电源冲突
2.2 电平标准与保护措施
GM-3568JHF的UART接口支持多种电平标准:
- TTL电平(3.3V)
- RS232(需通过MAX3232等芯片转换)
- RS485(需通过MAX485等芯片转换)
在实际工程中建议:
- 长距离通信(>1米)使用RS485
- 工业环境添加TVS二极管保护
- 避免将3.3V TTL直接连接5V设备
3. 软件环境配置
3.1 PC端工具链准备
推荐使用以下串口调试工具组合:
-
Windows平台:
- 终端工具:MobaXterm(集成SSH/SFTP/串口)
- 专用调试:SecureCRT(支持脚本自动化)
- 轻量级选择:Tera Term(开源免费)
-
Linux平台:
bash复制# 安装minicom sudo apt install minicom # 配置串口(以/dev/ttyUSB0为例) minicom -D /dev/ttyUSB0 -b 115200
3.2 开发板驱动加载验证
通过SSH登录开发板后,检查UART设备节点:
bash复制# 查看系统识别到的UART设备
ls /dev/ttyS*
# 检查驱动加载情况
dmesg | grep tty
典型输出应包含:
code复制ttyS0 at MMIO 0xfe650000 (irq = 34, base_baud = 1500000) is a 16550A
ttyS4 at MMIO 0xfe660000 (irq = 35, base_baud = 1500000) is a 16550A
4. UART通信实战开发
4.1 应用程序编译与部署
开发板配套的SDK中提供了UART测试程序源码,位于:
code复制/opt/shimetapi/sdk/linux_demo/smdt_uart_rw/src
编译步骤:
bash复制# 进入源码目录
cd /opt/shimetapi/sdk/linux_demo/smdt_uart_rw/src
# 交叉编译(需提前配置好交叉编译工具链)
make CROSS_COMPILE=aarch64-linux-gnu-
# 部署可执行文件
cp bin/smdt_uart_rw /usr/local/bin/
4.2 程序使用详解
测试程序支持以下参数:
code复制Usage: smdt_uart_rw [options]
Options:
-d <device> Specify UART device node (default /dev/ttyS4)
-b <baudrate> Set baud rate (default 115200)
-t <timeout> Set read timeout in ms (default 1000)
-r Enable receive mode
-w <string> String to send
典型使用场景:
-
接收模式(持续监听串口):
bash复制
smdt_uart_rw -d /dev/ttyS4 -b 115200 -r -
发送模式(单次发送字符串):
bash复制smdt_uart_rw -d /dev/ttyS4 -w "HelloWorld" -
交互模式(发送后等待响应):
bash复制# 发送查询指令 smdt_uart_rw -w "AT+VER?\r\n" # 立即切换为接收模式 smdt_uart_rw -r -t 500
4.3 底层实现原理
程序的核心代码逻辑解析:
c复制// 串口初始化
int uart_init(const char *device, int baudrate) {
struct termios options;
fd = open(device, O_RDWR | O_NOCTTY);
tcgetattr(fd, &options);
// 设置波特率
cfsetispeed(&options, baudrate);
cfsetospeed(&options, baudrate);
// 8N1配置
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// 应用配置
tcsetattr(fd, TCSANOW, &options);
return fd;
}
// 数据发送
void uart_send(int fd, const char *data) {
write(fd, data, strlen(data));
fsync(fd); // 确保数据写入硬件缓冲区
}
// 数据接收(非阻塞)
int uart_receive(int fd, char *buffer, int timeout_ms) {
fd_set readfds;
struct timeval tv;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
if (select(fd+1, &readfds, NULL, NULL, &tv) > 0) {
return read(fd, buffer, BUFFER_SIZE);
}
return -1; // 超时
}
5. 高级应用与问题排查
5.1 工业通信协议实现
基于UART实现Modbus RTU协议的示例:
c复制// Modbus RTU帧校验计算
uint16_t crc16(uint8_t *buf, int len) {
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (uint16_t)buf[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
// 发送Modbus查询指令
void send_modbus_query(int fd, uint8_t addr, uint8_t func, uint16_t reg, uint16_t count) {
uint8_t frame[8];
frame[0] = addr;
frame[1] = func;
frame[2] = reg >> 8;
frame[3] = reg & 0xFF;
frame[4] = count >> 8;
frame[5] = count & 0xFF;
uint16_t crc = crc16(frame, 6);
frame[6] = crc & 0xFF;
frame[7] = crc >> 8;
write(fd, frame, 8);
}
5.2 常见问题排查指南
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无数据接收 | 线序接反 | 检查TXD/RXD交叉连接 |
| 乱码 | 波特率不匹配 | 确认双方波特率一致 |
| 数据截断 | 缓冲区溢出 | 增加读取频率或扩大缓冲区 |
| 通信不稳定 | 地线未接 | 确保GND可靠连接 |
| 无法打开设备 | 权限不足 | 执行chmod 666 /dev/ttyS* |
5.3 性能优化建议
-
DMA传输:对于高速UART(>1Mbps),启用DMA减少CPU占用
bash复制# 查看可用DMA通道 cat /proc/dma -
中断优化:调整内核串口缓冲区大小
bash复制# 临时设置(单位:字节) echo 4096 > /sys/class/tty/ttyS4/rx_buffer_size echo 4096 > /sys/class/tty/ttyS4/tx_buffer_size -
实时性保障:为串口进程设置CPU亲和性
bash复制
taskset -pc 3 $(pidof smdt_uart_rw)
6. 扩展应用案例
6.1 多串口负载均衡
利用GM-3568JHF的多个UART接口实现数据分流:
bash复制# 启动多个接收实例
smdt_uart_rw -d /dev/ttyS4 -r > log1.txt &
smdt_uart_rw -d /dev/ttyS7 -r > log2.txt &
smdt_uart_rw -d /dev/ttyS8 -r > log3.txt &
6.2 与FPGA的协同工作
通过UART向FPGA发送控制指令的典型流程:
- ARM通过UART发送控制字(如0x01)
- FPGA接收并解析指令
- FPGA执行相应操作(如读取传感器)
- 通过UART返回数据给ARM
FPGA端Verilog示例:
verilog复制always @(posedge clk) begin
if (uart_rx_valid) begin
case (uart_rx_data)
8'h01: begin // 读取温度
uart_tx_data <= temp_sensor;
uart_tx_valid <= 1;
end
8'h02: begin // 控制LED
led <= uart_rx_data[0];
end
endcase
end
end
在实际调试这类异构系统时,建议先用逻辑分析仪抓取UART信号波形,验证物理层通信正常后再进行上层协议开发。