保姆级教程:在Linux 3.10内核下为CH432T SPI转串口芯片编写稳定驱动(附FIFO配置避坑点)

张开发
2026/5/3 8:09:01 15 分钟阅读
保姆级教程:在Linux 3.10内核下为CH432T SPI转串口芯片编写稳定驱动(附FIFO配置避坑点)
Linux 3.10内核下CH432T SPI转串口驱动开发实战指南在嵌入式系统开发中串口通信是最基础也最关键的接口之一。当项目需要扩展多个串口而硬件资源有限时SPI转串口芯片如CH432T就成为了理想选择。本文将深入探讨如何在Linux 3.10内核环境下为CH432T芯片开发稳定可靠的驱动程序特别关注SPI配置、寄存器操作和FIFO性能优化等核心问题。1. CH432T芯片基础与开发环境搭建CH432T是一款通过SPI接口扩展双串口的芯片支持最高4Mbps的SPI通信速率和最高3Mbps的串口波特率。在开始驱动开发前我们需要做好以下准备工作硬件连接确认确保CH432T的SPI接口正确连接到主控芯片如LS2K1000包括SCLK、MOSI、MISO和CS信号线Linux内核版本确认检查内核版本确认为3.10并准备好对应的内核头文件和开发工具链芯片手册获取准备好CH432T的技术手册CH432DS1.pdf这是驱动开发的重要参考开发环境配置示例# 安装必要的开发工具 sudo apt-get install build-essential libncurses-dev bison flex # 下载并解压Linux 3.10内核源码 wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.10.tar.xz tar -xvf linux-3.10.tar.xz # 配置交叉编译工具链以MIPS架构为例 export CROSS_COMPILEmipsel-linux-gnu- export ARCHmips2. SPI接口配置与通信协议实现CH432T的SPI接口支持模式0和模式3正确的SPI配置是驱动工作的基础。我们需要在内核驱动中正确设置SPI控制器参数。2.1 SPI模式配置根据芯片手册CH432T支持以下两种SPI模式SPI模式CPOLCPHA特点模式000时钟空闲低电平数据在上升沿采样模式311时钟空闲高电平数据在下降沿采样在驱动代码中我们需要这样配置SPI模式static struct spi_board_info ch432t_spi_device { .modalias ch432t, .max_speed_hz 6250000, // 6.25MHz SPI时钟 .bus_num 0, // SPI总线号 .chip_select 0, // 片选信号 .mode SPI_MODE_0, // SPI模式0 };2.2 SPI通信协议实现CH432T的SPI通信采用特定的协议格式每个SPI传输由地址码和数据组成地址码格式位1传输方向1写0读位5-2寄存器地址位7-6保留位通常设为0读写操作流程写操作发送地址码最高位为1后跟一个字节的待写数据读操作发送地址码最高位为0后读取一个字节的数据驱动中实现SPI读写的核心函数static int ch432t_spi_write(struct spi_device *spi, u8 addr, u8 data) { u8 tx_buf[2] {addr | 0x80, data}; // 设置写标志位 struct spi_transfer t { .tx_buf tx_buf, .len 2, }; return spi_sync_transfer(spi, t, 1); } static int ch432t_spi_read(struct spi_device *spi, u8 addr, u8 *data) { u8 tx_buf[1] {addr 0x7F}; // 清除写标志位 u8 rx_buf[1]; struct spi_transfer t[] { {.tx_buf tx_buf, .len 1}, {.rx_buf rx_buf, .len 1}, }; int ret spi_sync_transfer(spi, t, ARRAY_SIZE(t)); if (!ret) *data rx_buf[0]; return ret; }3. 关键寄存器配置与串口初始化CH432T的功能通过一系列寄存器控制正确配置这些寄存器是确保串口正常工作的关键。3.1 重要寄存器功能概述寄存器名称功能描述FCRFIFO控制寄存器控制FIFO使能、清除和中断触发阈值LCR线路控制寄存器设置数据位、停止位、奇偶校验等串口参数MCR调制解调器控制寄存器控制硬件流控、环回测试等LSR线路状态寄存器提供发送/接收状态和错误指示DLL/DLM波特率分频器设置串口通信波特率3.2 串口初始化流程完整的串口初始化应包括以下步骤复位芯片通过写FCR寄存器复位发送和接收FIFO设置波特率先设置LCR的DLAB位为1写入DLL和DLM寄存器最后清除DLAB位配置串口参数数据位长度通常8位停止位数量1或2位奇偶校验模式启用FIFO设置FCR寄存器的FIFOEN位设置中断触发阈值根据应用需求配置接收FIFO的中断触发点初始化代码示例int ch432t_uart_init(struct spi_device *spi) { int ret; // 1. 复位FIFO ret ch432t_spi_write(spi, CH432_REG_FCR, CH432_FCR_TFIFORST | CH432_FCR_RFIFORST); if (ret) return ret; // 2. 设置波特率为115200 // 先设置DLAB1 ret ch432t_spi_write(spi, CH432_REG_LCR, CH432_LCR_DLAB); if (ret) return ret; // 写入波特率分频器 (假设基准时钟为1.8432MHz) // 分频值 1843200/(16*115200) 1 ret ch432t_spi_write(spi, CH432_REG_DLL, 1); if (ret) return ret; ret ch432t_spi_write(spi, CH432_REG_DLM, 0); if (ret) return ret; // 清除DLAB设置串口参数8数据位1停止位无校验 ret ch432t_spi_write(spi, CH432_REG_LCR, CH432_LCR_WORDSZ_8 | CH432_LCR_STOPBIT_1); if (ret) return ret; // 3. 启用FIFO并设置触发阈值 ret ch432t_spi_write(spi, CH432_REG_FCR, CH432_FCR_FIFOEN | CH432_FCR_RECVTG_14); if (ret) return ret; return 0; }4. FIFO性能优化与稳定性调优FIFO的正确配置和使用是保证CH432T稳定工作的关键特别是在高波特率下。4.1 FIFO溢出问题分析在115200波特率下串口接收一个字节需要约86.8μs而接收16字节FIFO满需要约1.39ms。如果SPI总线被长时间占用导致无法及时读取FIFO数据就会发生溢出。SPI总线时间计算6.25MHz时钟传输1bit时间160ns传输1字节时间1.28μs完整SPI交互4字节5.12μs理论实测约20μs4.2 优化策略与实现为了避免FIFO溢出和SPI总线占用问题我们采取以下优化措施合理设置接收FIFO中断触发阈值根据应用场景选择4、8或14字节触发中断平衡中断频率和响应时间优化SPI总线访问策略发送数据时分批进行避免长时间占用总线在适当位置插入调度点让出CPU实现高效的中断服务程序快速读取FIFO数据到内核缓冲区减少中断服务程序中的复杂操作优化后的发送函数实现static int ch432t_uart_write(struct uart_port *port, const u8 *buf, int count) { struct ch432t_data *priv port-private_data; int remaining count; int chunk; int ret; while (remaining 0) { // 每次最多发送14字节避免长时间占用SPI总线 chunk min(remaining, 14); ret ch432t_spi_write_bulk(priv-spi, CH432_REG_THR, buf, chunk); if (ret) return ret; buf chunk; remaining - chunk; // 每发送14字节后让出CPU if (remaining 0) schedule_timeout_uninterruptible(1); } return count; }4.3 中断处理优化高效的中断处理程序对性能至关重要。以下是优化的中断处理流程快速判断中断源读取IIR寄存器确定中断类型批量处理接收数据一次读取所有可用数据减少SPI访问次数错误处理检查LSR寄存器处理可能的通信错误唤醒读进程如果有进程等待数据唤醒它中断处理代码框架static irqreturn_t ch432t_interrupt(int irq, void *dev_id) { struct uart_port *port dev_id; struct ch432t_data *priv port-private_data; u8 iir, lsr; u8 buf[16]; int count; // 读取中断标识寄存器 ch432t_spi_read(priv-spi, CH432_REG_IIR, iir); // 处理接收中断 if (iir CH432_IIR_RECV) { do { // 读取线路状态寄存器 ch432t_spi_read(priv-spi, CH432_REG_LSR, lsr); // 计算可读取的字节数 count (lsr CH432_LSR_DATARDY) ? 16 : 0; if (count 0) { // 批量读取数据 ch432t_spi_read_bulk(priv-spi, CH432_REG_RBR, buf, count); tty_insert_flip_string(port-state-port, buf, count); } } while (count 0); tty_flip_buffer_push(port-state-port); } // 处理发送中断 if (iir CH432_IIR_SEND) { // 唤醒可能的写等待进程 uart_write_wakeup(port); } return IRQ_HANDLED; }5. 驱动测试与调试技巧开发完成后我们需要对驱动进行全面的测试和调试确保其稳定性和可靠性。5.1 基本功能测试回环测试短接串口的TX和RX引脚通过终端发送数据检查是否能正确回显波特率测试在不同波特率下测试数据传输特别关注高波特率(如115200、230400)下的稳定性长时间压力测试持续发送大量数据检查是否有丢包或错误5.2 性能监测与优化SPI总线利用率监测使用示波器观察SPI信号波形确保没有长时间占用总线的情况中断延迟测量测量从中断发生到中断服务程序开始执行的时间优化内核配置减少延迟FIFO状态监控定期读取LSR寄存器检查溢出错误调整FIFO触发阈值优化性能5.3 常见问题排查数据丢失问题检查SPI时钟是否稳定确认FIFO触发阈值设置合理验证中断处理程序效率通信错误问题检查线路状态寄存器(LSR)的错误标志位验证串口参数(波特率、数据位等)设置系统稳定性问题检查驱动中的锁机制是否正确验证内存管理是否有泄漏调试技巧示例# 查看内核消息获取驱动调试信息 dmesg | grep ch432t # 使用spidev工具测试SPI通信 spidev_test -D /dev/spidev0.0 -s 6250000 -p \x01\x02\x03 # 使用stty设置串口参数 stty -F /dev/ttyCH432UART0 115200 cs8 -parenb -cstopb在实际项目中我们发现最关键的优化点是平衡SPI总线访问频率和FIFO读取时机。通过将发送数据分块处理并适时让出CPU成功解决了高负载下的数据丢失问题。同时合理设置接收FIFO触发阈值通常8字节是一个较好的折衷可以显著提高系统响应速度而不增加CPU负担。

更多文章