content_views"
class="markdown_views prism-atom-one-dark">
前言
本文简单介绍了龙芯中的uart通信以及使用方法。
一、代码结构解析
1. 头文件部分
<code class="prism language-c">class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><stdio.h> class="token comment">// 标准输入输出
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><stdlib.h> class="token comment">// 系统函数库(如system)
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><time.h> class="token comment">// 时间相关函数
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><unistd.h> class="token comment">// POSIX API(如usleep)
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><fcntl.h> class="token comment">// 文件控制(如open)
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><termios.h> class="token comment">// 串口配置结构体
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><errno.h> class="token comment">// 错误号定义
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><string.h> class="token comment">// 字符串操作
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><sys/mman.h> class="token comment">// 内存映射
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><sys/types.h> class="token comment">// 系统数据类型
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><sys/stat.h> class="token comment">// 文件状态
code>
作用
ckquote> 作用:包含Linux环境下串口通信和系统操作所需的头文件。
ckquote>
2. 宏定义与全局变量
<code class="prism language-c">class="token macro property">class="token directive-hash">#class="token directive keyword">define class="token macro-name">EXPORT class="token string">"/sys/class/gpio/export" class="token comment">// GPIO导出路径
class="token macro property">class="token directive-hash">#class="token directive keyword">define class="token macro-name">DEV_NAME class="token string">"/dev/ttyS2" class="token comment">// 龙芯UART设备节点
class="token macro property">class="token directive-hash">#class="token directive keyword">define class="token macro-name">pwm1 class="token expression">class="token number">1 class="token comment">// PWM通道定义
code>
ckquote> - 龙芯处理器(如LS2K1000)的UART设备节点通常为**/dev/ttyS0~ /dev/ttyS3**c;对应硬件UART0~UART3。
- PWM通道路径需根据具体硬件确定c;可能与SoC的PWM控制器映射相关。
ckquote>
3. 主函数流程
<code class="prism language-c">class="token keyword">int class="token function">mainclass="token punctuation">(class="token punctuation">) class="token punctuation">{class="token comment">// 初始化UARTuart_fd class="token operator">= class="token function">open_portclass="token punctuation">(DEV_NAMEclass="token punctuation">)class="token punctuation">; class="token comment">// 打开串口设备class="token function">set_portclass="token punctuation">(uart_fdclass="token punctuation">, class="token number">115200class="token punctuation">, class="token number">8class="token punctuation">, class="token char">'N'class="token punctuation">, class="token number">1class="token punctuation">)class="token punctuation">; class="token comment">// 配置波特率等参数class="token keyword">whileclass="token punctuation">(class="token number">1class="token punctuation">) class="token punctuation">{class="token function">usleepclass="token punctuation">(class="token number">500000class="token punctuation">)class="token punctuation">; class="token comment">// 延时500msclass="token function">memsetclass="token punctuation">(read_bufclass="token punctuation">, class="token number">0class="token punctuation">, class="token keyword">sizeofclass="token punctuation">(read_bufclass="token punctuation">)class="token punctuation">)class="token punctuation">;class="token function">tcflushclass="token punctuation">(uart_fdclass="token punctuation">, TCOFLUSHclass="token punctuation">)class="token punctuation">; class="token comment">// 清空缓冲区nread class="token operator">= class="token function">readclass="token punctuation">(uart_fdclass="token punctuation">, read_bufclass="token punctuation">, class="token number">4class="token punctuation">)class="token punctuation">;class="token comment">// 尝试读取数据write_bufclass="token punctuation">[class="token number">0class="token punctuation">] class="token operator">= class="token number">6class="token punctuation">; class="token comment">// 发送数据6class="token function">Uart_Sendclass="token punctuation">(uart_fdclass="token punctuation">, write_bufclass="token punctuation">, class="token number">1class="token punctuation">)class="token punctuation">; class="token comment">// 发送单字节class="token punctuation">}
class="token punctuation">}
code>
关键点
ckquote> - tcflush(uart_fd, TCOFLUSH)用于清空输出缓冲区c;确保发送数据无残留。
- 龙芯UART的时钟源由CPU时钟分频而来c;需确保波特率计算值与实际硬件匹配。
ckquote>
<code class="prism language-c">class="token keyword">int class="token function">Uart_Sendclass="token punctuation">(class="token keyword">int fdclass="token punctuation">, class="token keyword">char class="token operator">*send_bufclass="token punctuation">, class="token keyword">int data_lenclass="token punctuation">) class="token punctuation">{class="token keyword">return class="token function">writeclass="token punctuation">(fdclass="token punctuation">, send_bufclass="token punctuation">, data_lenclass="token punctuation">)class="token punctuation">; class="token comment">// 直接调用系统写函数
class="token punctuation">}
code>
ckquote> 龙芯UART驱动基于8250驱动框架c;用户空间通过write()直接操作设备节点。
ckquote>
5. 串口配置函数(set_port)
<code class="prism language-c">class="token keyword">int class="token function">set_portclass="token punctuation">(class="token keyword">int fdclass="token punctuation">, class="token keyword">int nSpeedclass="token punctuation">, class="token keyword">int nBitsclass="token punctuation">, class="token keyword">char nEventclass="token punctuation">, class="token keyword">int nStopclass="token punctuation">) class="token punctuation">{class="token keyword">struct class="token class-name">termios newtioclass="token punctuation">;class="token comment">// 配置数据位、校验位、停止位newtioclass="token punctuation">.c_cflag class="token operator">|= CLOCAL class="token operator">| CREADclass="token punctuation">; class="token comment">// 本地连接+使能接收class="token comment">// 波特率设置(关键代码段)class="token function">cfsetospeedclass="token punctuation">(class="token operator">&newtioclass="token punctuation">, B115200class="token punctuation">)class="token punctuation">; class="token comment">// 输出波特率class="token function">cfsetispeedclass="token punctuation">(class="token operator">&newtioclass="token punctuation">, B115200class="token punctuation">)class="token punctuation">; class="token comment">// 输入波特率class="token comment">// 应用配置class="token function">tcsetattrclass="token punctuation">(fdclass="token punctuation">, TCSANOWclass="token punctuation">, class="token operator">&newtioclass="token punctuation">)class="token punctuation">;
class="token punctuation">}
code>
ckquote> 1.波特率精度依赖时钟分频器c;需在硬件设计中确认UART时钟源频率。
2.若需更高波特率(如3Mbps)c;可能需要修改内核驱动中的分频参数。
ckquote>
6. GPIO控制函数
<code class="prism language-c">class="token keyword">void class="token function">export_gpioclass="token punctuation">(class="token keyword">int gpioclass="token punctuation">) class="token punctuation">{class="token function">systemclass="token punctuation">(class="token string">"echo XX > /sys/class/gpio/export"class="token punctuation">)class="token punctuation">; class="token comment">// 通过sysfs操作
class="token punctuation">}
code>
龙芯GPIO特性
ckquote> 1.GPIO编号需参考具体开发板手册c;如LS2K1000的GPIO可能按Bank分组管理。
ckquote>
ckquote> 2.部分GPIO可能复用为其他功能(如UART)c;需配置引脚复用寄存器。
ckquote>
7. PWM控制函数
<code class="prism language-c">class="token keyword">int class="token function">pwm_configclass="token punctuation">(class="token keyword">unsigned class="token keyword">int pwmclass="token punctuation">, class="token keyword">unsigned class="token keyword">int periodclass="token punctuation">, duty_cycleclass="token punctuation">) class="token punctuation">{class="token comment">// 通过sysfs设置周期和占空比class="token function">writeclass="token punctuation">(fdclass="token punctuation">, buf_pclass="token punctuation">, len_pclass="token punctuation">)class="token punctuation">; class="token comment">// 写入period值class="token function">writeclass="token punctuation">(fdclass="token punctuation">, buf_dclass="token punctuation">, len_dclass="token punctuation">)class="token punctuation">; class="token comment">// 写入duty_cycle
class="token punctuation">}
code>
龙芯PWM实现
ckquote> 1.PWM控制器可能集成在SoC中c;需内核启用pwm-ls等专用驱动。
2.周期(period)单位通常为纳秒(ns)c;需根据硬件限制设置合理值。
ckquote>
1. 硬件架构
控制器类型
ckquote> 控制器类型:龙芯UART兼容NS16550A标准c;支持DMA和FIFO模式。
ckquote>
时钟源
ckquote> 时钟源:通常由APB总线时钟分频得到c;例如LS2K1000的APB时钟为100MHz。
ckquote>
寄存器映射
ckquote> 寄存器映射:通过内存映射访问c;用户空间无需直接操作寄存器。
ckquote>
2. 关键寄存器
ckquote> 寄存器 功能 偏移地址
RBR 接收缓冲 0x00
THR 发送保持 0x00
IER 中断使能 0x01
FCR FIFO控制 0x02
LCR 线路控制 0x03
MCR Modem控制 0x04
LSR 线路状态 0x05
ckquote>
3. 驱动配置
内核配置
ckquote> 内核配置:确保启用CONFIG_SERIAL_8250和CONFIG_SERIAL_8250_CONSOLE。
ckquote>
设备树配置
ckquote> 设备树配置:
uart0: serial@1fe40000 {
compatible = “ns16550a”;
reg = <0x1fe40000 0x100>;
interrupts = <8>;
clock-frequency = <100000000>; // APB时钟
};
ckquote>
4. 波特率计算
公式
ckquote> 公式:波特率 = 时钟频率 / (16 * 分频系数)
ckquote>
示例
ckquote> 示例:若时钟为100MHzc;要求115200波特率:
分频系数 = 100000000 / (16 * 115200) ≈ 54.25
实际写入分频寄存器值:54(误差约0.46%)
ckquote>
三、代码优化建议
错误处理增强
<code class="prism language-c">class="token comment">// 在open_port中添加重试逻辑
class="token keyword">int class="token function">open_portclass="token punctuation">(class="token keyword">char class="token operator">*dirclass="token punctuation">) class="token punctuation">{class="token keyword">int fdclass="token punctuation">, retries class="token operator">= class="token number">3class="token punctuation">;class="token keyword">whileclass="token punctuation">(retriesclass="token operator">--class="token punctuation">) class="token punctuation">{fd class="token operator">= class="token function">openclass="token punctuation">(dirclass="token punctuation">, O_RDWR class="token operator">| O_NOCTTYclass="token punctuation">)class="token punctuation">;class="token keyword">ifclass="token punctuation">(fd class="token operator">>= class="token number">0class="token punctuation">) class="token keyword">return fdclass="token punctuation">;class="token function">usleepclass="token punctuation">(class="token number">100000class="token punctuation">)class="token punctuation">; class="token comment">// 等待100ms重试class="token punctuation">}class="token keyword">return class="token operator">-class="token number">1class="token punctuation">;
class="token punctuation">}
code>
非阻塞读取优化
<code class="prism language-c">class="token comment">// 使用select实现超时读取
fd_set readsetclass="token punctuation">;
class="token function">FD_ZEROclass="token punctuation">(class="token operator">&readsetclass="token punctuation">)class="token punctuation">;
class="token function">FD_SETclass="token punctuation">(uart_fdclass="token punctuation">, class="token operator">&readsetclass="token punctuation">)class="token punctuation">;
class="token keyword">struct class="token class-name">timeval timeout class="token operator">= class="token punctuation">{class="token number">0class="token punctuation">, class="token number">500000class="token punctuation">}class="token punctuation">; class="token comment">// 500ms超时
class="token keyword">ifclass="token punctuation">(class="token function">selectclass="token punctuation">(uart_fdclass="token operator">+class="token number">1class="token punctuation">, class="token operator">&readsetclass="token punctuation">, class="token constant">NULLclass="token punctuation">, class="token constant">NULLclass="token punctuation">, class="token operator">&timeoutclass="token punctuation">) class="token operator">> class="token number">0class="token punctuation">) class="token punctuation">{class="token function">readclass="token punctuation">(uart_fdclass="token punctuation">, bufclass="token punctuation">, lenclass="token punctuation">)class="token punctuation">;
class="token punctuation">}
code>
PWM配置封装
<code class="prism language-c">class="token keyword">void class="token function">pwm_initclass="token punctuation">(class="token keyword">int pwmclass="token punctuation">, class="token keyword">int periodclass="token punctuation">, class="token keyword">int dutyclass="token punctuation">) class="token punctuation">{class="token function">pwm_exportclass="token punctuation">(pwmclass="token punctuation">)class="token punctuation">;class="token function">pwm_configclass="token punctuation">(pwmclass="token punctuation">, periodclass="token punctuation">, dutyclass="token punctuation">)class="token punctuation">;class="token function">pwm_enableclass="token punctuation">(pwmclass="token punctuation">)class="token punctuation">;
class="token punctuation">}
code>
四、龙芯开发注意事项
串口引脚复用
ckquote> 确认硬件设计中UART的TX/RX引脚未被复用为GPIO或其他功能c;需通过PINCTRL配置。
ckquote>
DMA模式启用
ckquote> 对于高速传输(>1Mbps)c;可在内核驱动中启用DMA模式:
ckquote>
<code class="prism language-c">class="token comment">// 修改驱动源码(drivers/tty/serial/8250/8250_port.c)
upclass="token operator">->dma class="token operator">= class="token function">dma_request_slave_channelclass="token punctuation">(devclass="token punctuation">, class="token string">"rx-tx"class="token punctuation">)class="token punctuation">;
code>
硬件流控配置
ckquote> 若需RTS/CTS流控c;在termios中设置:
ckquote>
<code class="prism language-c">newtioclass="token punctuation">.c_cflag class="token operator">|= CRTSCTSclass="token punctuation">;
code>
系统稳定性
ckquote> 长时间运行需监控UART错误状态:
ckquote>
<code class="prism language-c">class="token keyword">int statusclass="token punctuation">;
class="token function">ioctlclass="token punctuation">(uart_fdclass="token punctuation">, TIOCMGETclass="token punctuation">, class="token operator">&statusclass="token punctuation">)class="token punctuation">;
class="token keyword">ifclass="token punctuation">(status class="token operator">& TIOCM_CTSclass="token punctuation">) class="token punctuation">{ class="token comment">/* 处理CTS状态 */ class="token punctuation">}
code>
以上分析结合了代码逻辑与龙芯平台特性c;实际开发中需参考具体硬件手册调整参数。