作者:Hello,Panda;文章来源:ZYNQ分享客
大家好,好久没没冒泡了,今天分享一个小设计:就是使用CH346C这颗USB2.0桥接SPI Slave FIFO(40Mbps)的芯片与计算机通信,当然也连带其高速串口功能(最高15Mbuad/s)。
CH346是一款USB2.0转被动FIFO(并口或SPI)、异步串口的桥接芯片。本设计电路将其设计成为模式1(被动SPI+1个异步UART),其中被动SPI最高支持40MHz时钟访问,异步UART最高支持15Mbaud/s的通讯速率。本例程实现UART收发和通过SPI写FIFO推送数据流到计算机两个核心功能。设计目标为:(1)UART收发,波特率2400~5Mbaud/s可调,收发数据格式可调;(2)SPI读写FIFO传输数据,SPI总线时钟40MHz。
一、硬件描述
硬件原理图见下图1所示,CFG0配置为了高电平,芯片工作在模式0/1。芯片的SPI总线、FIFO流控信号和UART与FPGA连接。

图1 CH346C电路原理图
YSPL0015E搭载Lattice LIFCL-40-7MG121I FPGA芯片,下表1是信号对应的FPGA引脚对照表。

二、 UART收发IP概述
如下图2是UART收发IP的系统框图。

图2 UART收发IP的系统框图
IP顶层为uart_top_v1.v,设计为3个独立模块,分别是UART发送模块uart_tx_v1,uart接收模块uart_rx_v1和txfifo模块,三个独立模块文件在顶层uart_top_v1.v中例化调用。UART收发IP支持以下功能:
波特率支持从2400~5Mbuad/s的常用波特率值;
输入时钟i_clk支持100MHz、125MHz、148.5MHz、150MHz、156.25MHz和200MHz中的一种,根据按波特率计算得到的最小误差选择最合适的一个使用;
支持无效验、奇效验和偶效验,支持对输入的i_uart_rxd消毛刺滤波。
2.1 UART发送模块
串口返送模块为一个独立的uart_tx_v1.v文件,包括波特率发生器、UART发送状态机和极性效验功能。在i_uart_tx_enable使能时,检测fifo是否有数(i_txfifo_alempty为高电平表示fifo没有数),若有数,则将数据实时发出。发送状态机考虑错误退出机制,下表2是uart发送模块信号端口描述。模块输入参数P_CLK_DIV用于波特率相关计数等。

2.2 UART接收模块
串口返送模块为一个独立的uart_rx_v1.v文件,包括对i_uart_rxd信号毛刺滤波、数据接收状态机等。每收到一个字节数据后实时输出,同时o_rx_data_valid信号与有效数据对齐,该信号高电平有效。接收状态机考虑错误退出机制,下表3是UART接收模块的信号端口描述。

2.3txfifo模块
该模块设计为first-word-fall-through(FWFT)模式以保证读取时序的便捷性,使能almost full和almost empty功能以检查fifo中的数据状态,txfifo的输入输出数据见图1。
2.4 顶层模块
顶层模块以一个单独的uart_top_v1.v存在,下表4是UART收发IP的端口描述。

调用顶层模块时,应用只需要检查o_txfifo_alfull信号是否为1,如果为1则禁止继续向txfifo写入数据。
2.5 测试结果
在实现调试之前需要先将CH346内部固件设置为模式1(CFG0只能选择模式0/1和模式2),该过程通过南京沁恒的工具“CH34xSerCfg”完成,配置见面见下图3所示。先选中①处弹出②处的配置界面,将工作模式选为“1”,模式1下的IO配置见方框处。最后,可以根据需求填写设备商、产品字符和序列号字符。最后,点击“写入配置”按钮将配置写入到芯片内部的EEPROM中。

代码主体由Deepseek-V4完成,在Radaint编译后下载到FPGA运行结果如下图4所示。

三、 SPI收发器
该SPI收发器用于CH346C读写Slave FIFO数据,计算机客户端使用WCH的测试DEMO收发数据,驱动使用CH346DRV专用驱动。用户可以调用USB转被动SPI接口函数库编写所需的功能程序。
3.1 顶层模块
SPI接口主机需要工作在时序模式0或时序模式3,下图5是运行流程图。
SPI主机向CH346C芯片发送数据(写模式)的流程:
步骤 1:SPI 接口主机控制 SPI_RWS引脚输出高电平,通知CH346 芯片需要切换为写模式;
步骤 2:检测 CH346 芯片的 SPI_WRNF 引脚状态,如果检测到低电平表示 CH346 芯片的接收 FIFO还有空间可以接收一包(最大为 512 字节)数据,则执行步骤 3;如果检测到高电平表示CH346 芯片的接收 FIFO 已满,则重新执行步骤 2;
步骤 3:SPI 接口主机执行数据发送操作,向CH346 芯片最多发送 512 字节数据,并等待数据发送结束;
步骤 4:如果 SPI 主机需要继续发送数据,则重新执行步骤 2;
SPI接口主机从CH346芯片读取数据(读模式)流程:
步骤 1:SPI 接口主机控制 SPI_RWS 引脚输出低电平,通知 CH346 芯片需要切换为读模式,等待SPI_WRNF引脚拉高或者等待至少6us(仅从写模式切换到读模式时需要等待);
步骤 2:检测 CH346 芯片的 SPI_RDNE 引脚状态,如果检测到低电平表示 CH346 芯片的发送 FIFO中有数据可以读取,则执行步骤 3;如果检测到高电平,表示 CH346 芯片的发送 FIFO 无数据可以读取,则重新执行步骤 2;
步骤 3:SPI 接口主机执行数据读取操作,根据应用方式不同有以下 3 种进行读取方式:
方式 1:拉低 SCS,从 CH346 芯片读取 4 个字节的本包数据长度 L(低字节在前,最大为 512 字节),再根据实际长度读取 L 个字节的数据,拉高 SCS;
方式 2:拉低 SCS,从 CH346 芯片读取 4 个字节的本包数据长度 L(低字节在前,最大为 512 字节),拉高 SCS;再次拉低 SCS,读取 4+L 个字节的数据,拉高 SCS;
方式 3:拉低 SCS,从 CH346 芯片读取固定 516 个字节的数据,前 4 个字节为本包数据长度,后512字节为实际数据,拉高SCS;
步骤 4:如果 SPI 主机需要继续读取,重新执行步骤 2。

图5收发状态机流程图
Slave FIFO可以用于发送中等数量的数据到计算机或下载中等数据的数据到单板,实测SPI时钟运行在40MHz时,实测数据带宽为4.58MByte/s。下表5是SPI收发器的顶层端口和参数表。



3.2 调用要点
调用SPI收发器时,控制信号设计要点:
需要向SPI Slave FIFO写数时,先检查i_wrnf_n信号不为高,然后把发数FIFO复位(i_wfifo_reset=1),待复位完成后,连续向写数FIFO写入不超过512字节的待发数据,数据写入完成发起写访问请求(i_spi_start=1,同时正确填写i_spi_rdwr和i_spi_wbytes),待o_spi_done后一次写数据完成。
需要从SPI Slave FIFO读数时,先检查i_rdnc_n状态不为高,然后将读数FIFO复位(i_rfifo_reset=1),待复位完成后发起读访问请求(i_spi_start=1,同时正确填写i_spi_rdwr),待o_spi_done后一次写数据完成。顶层状态机可o_spi_rbytes的值从读数FIFO中读出同等字节的数据。
需要特别注意的是,CH346C需要在计算机客户端软件运行后方能操作SPI Slave FIFO,否则可能会发生意外错误。因此,需要将SPI读写CH346C坐成受控,比如在计算机客户端软件在启动后通过串口向设备发送一条准备就绪命令。本测试FPGA工程中是例化了一个“Virtual Switch”,在计算机客户端Demo启动后手动写‘1’使能FPGA收发SPI的逻辑。
3.3 测试结果
测试结果见图6,从图6可以看到,接收到的数据和FPGA逻辑里面产生的发送数据一致,RxSpeed为4.58MB/s,与设计预期一致。

图6 CH346C Slave FIFO传输实测结果
今天的分享到此结束。

