文章目录
- 前言
- 一、代码结构解析
- 1. 头文件部分
- 作用
- 2. 宏定义与全局变量
- 龙芯特性
- 3. 主函数流程
- 关键点
- 4. UART发送函数
- 龙芯实现
- 5. 串口配置函数(set_port)
- 龙芯注意事项
- 6. GPIO控制函数
- 龙芯GPIO特性
- 7. PWM控制函数
- 龙芯PWM实现
- 二、龙芯UART深度解析
- 1. 硬件架构
- 控制器类型
- 时钟源
- 寄存器映射
- 2. 关键寄存器
- 3. 驱动配置
- 内核配置
- 设备树配置
- 4. 波特率计算
- 公式
- 示例
- 三、代码优化建议
- 错误处理增强
- 非阻塞读取优化
- PWM配置封装
- 四、龙芯开发注意事项
- 串口引脚复用
- DMA模式启用
- 硬件流控配置
- 系统稳定性
前言
本文简单介绍了龙芯中的uart通信以及使用方法。
一、代码结构解析
1. 头文件部分
#include <stdio.h> // 标准输入输出
#include <stdlib.h> // 系统函数库(如system)
#include <time.h> // 时间相关函数
#include <unistd.h> // POSIX API(如usleep)
#include <fcntl.h> // 文件控制(如open)
#include <termios.h> // 串口配置结构体
#include <errno.h> // 错误号定义
#include <string.h> // 字符串操作
#include <sys/mman.h> // 内存映射
#include <sys/types.h> // 系统数据类型
#include <sys/stat.h> // 文件状态
作用
作用:包含Linux环境下串口通信和系统操作所需的头文件。
2. 宏定义与全局变量
#define EXPORT "/sys/class/gpio/export" // GPIO导出路径
#define DEV_NAME "/dev/ttyS2" // 龙芯UART设备节点
#define pwm1 1 // PWM通道定义
龙芯特性
- 龙芯处理器(如LS2K1000)的UART设备节点通常为**/dev/ttyS0~ /dev/ttyS3**,对应硬件UART0~UART3。
- PWM通道路径需根据具体硬件确定,可能与SoC的PWM控制器映射相关。
3. 主函数流程
int main() {// 初始化UARTuart_fd = open_port(DEV_NAME); // 打开串口设备set_port(uart_fd, 115200, 8, 'N', 1); // 配置波特率等参数while(1) {usleep(500000); // 延时500msmemset(read_buf, 0, sizeof(read_buf));tcflush(uart_fd, TCOFLUSH); // 清空缓冲区nread = read(uart_fd, read_buf, 4);// 尝试读取数据write_buf[0] = 6; // 发送数据6Uart_Send(uart_fd, write_buf, 1); // 发送单字节}
}
关键点
- tcflush(uart_fd, TCOFLUSH)用于清空输出缓冲区,确保发送数据无残留。
- 龙芯UART的时钟源由CPU时钟分频而来,需确保波特率计算值与实际硬件匹配。
4. UART发送函数
int Uart_Send(int fd, char *send_buf, int data_len) {return write(fd, send_buf, data_len); // 直接调用系统写函数
}
龙芯实现
龙芯UART驱动基于8250驱动框架,用户空间通过write()直接操作设备节点。
5. 串口配置函数(set_port)
int set_port(int fd, int nSpeed, int nBits, char nEvent, int nStop) {struct termios newtio;// 配置数据位、校验位、停止位newtio.c_cflag |= CLOCAL | CREAD; // 本地连接+使能接收// 波特率设置(关键代码段)cfsetospeed(&newtio, B115200); // 输出波特率cfsetispeed(&newtio, B115200); // 输入波特率// 应用配置tcsetattr(fd, TCSANOW, &newtio);
}
龙芯注意事项
1.波特率精度依赖时钟分频器,需在硬件设计中确认UART时钟源频率。
2.若需更高波特率(如3Mbps),可能需要修改内核驱动中的分频参数。
6. GPIO控制函数
void export_gpio(int gpio) {system("echo XX > /sys/class/gpio/export"); // 通过sysfs操作
}
龙芯GPIO特性
1.GPIO编号需参考具体开发板手册,如LS2K1000的GPIO可能按Bank分组管理。
2.部分GPIO可能复用为其他功能(如UART),需配置引脚复用寄存器。
7. PWM控制函数
int pwm_config(unsigned int pwm, unsigned int period, duty_cycle) {// 通过sysfs设置周期和占空比write(fd, buf_p, len_p); // 写入period值write(fd, buf_d, len_d); // 写入duty_cycle
}
龙芯PWM实现
1.PWM控制器可能集成在SoC中,需内核启用pwm-ls等专用驱动。
2.周期(period)单位通常为纳秒(ns),需根据硬件限制设置合理值。
二、龙芯UART深度解析
1. 硬件架构
控制器类型
控制器类型:龙芯UART兼容NS16550A标准,支持DMA和FIFO模式。
时钟源
时钟源:通常由APB总线时钟分频得到,例如LS2K1000的APB时钟为100MHz。
寄存器映射
寄存器映射:通过内存映射访问,用户空间无需直接操作寄存器。
2. 关键寄存器
寄存器 功能 偏移地址
RBR 接收缓冲 0x00
THR 发送保持 0x00
IER 中断使能 0x01
FCR FIFO控制 0x02
LCR 线路控制 0x03
MCR Modem控制 0x04
LSR 线路状态 0x05
3. 驱动配置
内核配置
内核配置:确保启用CONFIG_SERIAL_8250和CONFIG_SERIAL_8250_CONSOLE。
设备树配置
设备树配置:
uart0: serial@1fe40000 {
compatible = “ns16550a”;
reg = <0x1fe40000 0x100>;
interrupts = <8>;
clock-frequency = <100000000>; // APB时钟
};
4. 波特率计算
公式
公式:波特率 = 时钟频率 / (16 * 分频系数)
示例
示例:若时钟为100MHz,要求115200波特率:
分频系数 = 100000000 / (16 * 115200) ≈ 54.25
实际写入分频寄存器值:54(误差约0.46%)
三、代码优化建议
错误处理增强
// 在open_port中添加重试逻辑
int open_port(char *dir) {int fd, retries = 3;while(retries--) {fd = open(dir, O_RDWR | O_NOCTTY);if(fd >= 0) return fd;usleep(100000); // 等待100ms重试}return -1;
}
非阻塞读取优化
// 使用select实现超时读取
fd_set readset;
FD_ZERO(&readset);
FD_SET(uart_fd, &readset);
struct timeval timeout = {0, 500000}; // 500ms超时
if(select(uart_fd+1, &readset, NULL, NULL, &timeout) > 0) {read(uart_fd, buf, len);
}
PWM配置封装
void pwm_init(int pwm, int period, int duty) {pwm_export(pwm);pwm_config(pwm, period, duty);pwm_enable(pwm);
}
四、龙芯开发注意事项
串口引脚复用
确认硬件设计中UART的TX/RX引脚未被复用为GPIO或其他功能,需通过PINCTRL配置。
DMA模式启用
对于高速传输(>1Mbps),可在内核驱动中启用DMA模式:
// 修改驱动源码(drivers/tty/serial/8250/8250_port.c)
up->dma = dma_request_slave_channel(dev, "rx-tx");
硬件流控配置
若需RTS/CTS流控,在termios中设置:
newtio.c_cflag |= CRTSCTS;
系统稳定性
长时间运行需监控UART错误状态:
int status;
ioctl(uart_fd, TIOCMGET, &status);
if(status & TIOCM_CTS) { /* 处理CTS状态 */ }
以上分析结合了代码逻辑与龙芯平台特性,实际开发中需参考具体硬件手册调整参数。