我们使用FPGA组织PC和DAC / ADC之间的交互

在现代数字世界中,需要对DAC / ADC(数字-模拟转换器/模-数转换器)是毫无疑问的:它们被用来从各种传感器的过程信号,音响设备,电视调谐器,视频输入卡,摄像机等



但是,由于硬件制造商设置的限制(例如,所用软件或如何控制设备),使用或调试DAC / ADC可能很困难。这建议您设计自己的交互模型。



在本文中,我们将考虑使用FPGA组织PC与DAC / ADC之间的交互的可能性。









前言



本文的主要目的是描述特定问题的解决方案,以及对集成电路(IC)交互界面的熟悉。此处不考虑DAC / ADC的主要目的。



本文需要一些有关面向对象的编程和电路的知识,因此,如果您不熟悉这些概念,建议从它们开始。



我希望第一次遇到电子设备通信问题的人的经验对某人有用。



祝大家好运,新成就!



一个关于界面的小型教育程序



免责声明



如果您熟悉用于IC通信的主要接口的结构,则可以安全地跳过这一点。



教育计划



, .



, (, .) . , .



, . , , , .. , . . – , . , . , .



, .





( ), :



  • «-»;
  • «»;
  • «» («»).


«-» — , . , — .







«» (, « » «») , . . , , , . .







( «») . , , , - . .









:



  • ;
  • ;
  • -.


, . . . , .







, . , , .







(-/)





:



  • ();
  • ();
  • ().


. .







, .

: , «» .







. .









:



  • ;
  • .


. . . ( – , – , , ). « » ( ). .







, , .







?



() SPI I2C UART.



I2C



I2C – . I2C . I2C «-», .



, , . , . 7- 16 . , 112 . I2C (SDA) (SCL).





I2C



SPI



SPI – , .



SPI «-». MOSI SCLK, . MISO, . SS.





SPI



UART



UART – – , .

RxD ( ) TxD ( ).



UART TxD . . UART , , UART , . , . 8 ( ), , .

UART «-». , UART . « » «».





UART





这是什么DAC?









首先,让我们定义所使用的DAC / ADC:



ADI公司的AD9993-EBZ调试板是一种结合了四个14位ADC和两个14位DAC的器件。



该IC的工作模式通过更改其内部寄存器的状态来控制。 AD9993使用66个寄存器,其存储(处理)的字长为8位,其地址由三位十六进制值(12个数据位)描述。支持两种类型的命令-读命令和写命令。换句话说,为了校正IC的操作,必须发送命令以将一些有效的8位值写入特定的寄存器地址。通过串行外围设备接口(SPI)可以访问该IC的寄存器,调试板上的连接通过40针FIFO_0连接器或通过额外安装的触点组实现。





像这样一个(FIFO_0-顶部灰色连接器)



SPI极限参数的基本要求:



  • 最大数据传输频率-25 MHz;
  • 同步信号发生线上的上下电平的持续时间为10 ns;
  • 数据传输线上和分辨率线上的电平设置时间-2 ns;
  • 数据传输线上和分辨率线上的电平保持时间-2 ns;
  • 从站的传输线上的一个数据位的有效保证时间为2 ns。


有关设备功能的完整说明,请参见其文档



制造商怎么说?



推荐的控制方案



根据AD9993-EBZ文档,推荐的控制IC的方法是使用ADI公司的HSC-ADC-EVALC调试板,该调试板通过40引脚端口连接到IC,并通过USB接口连接到PC。



SPIController用作控制软件。





推荐的





Analog Devices HSC-ADC-EVALC电路(基于Xilinx Virtex-4 FPGA)



缺点:



  • 高价。ADI公司官方网站上的调试板HSC-ADC-EVALC的价格为698.28美元。
  • 不方便的用户界面。SPIController软件除了具有写入和读取寄存器的主要功能外,还不具备保存或计划启动命令的功能。
  • . SPI SPIController, . Analog Devices, SPI.




SPIController



:



  • .


HSC-ADC-EVALC



应当注意,使用ADI公司的HSC-ADC-EVALC板作为DAC / ADC控制设备并不是其主要目的。



HSC-ADC-EVALC主要用作ADC的缓冲存储卡,但是如果所连接的卡支持SPI,它还具有通过SPI配置调试卡的功能。



自己的互动模型



使用中间设备的原因



显然,DAC / ADC与PC之间的交互无法直接组织,因为编程AD9993-EBZ的SPI并不是现代PC的典型接口。



为了解决这个问题,有必要使用一种中间设备,该设备会将计算机发送的USB接口的数据转换为IC支持的SPI接口格式。



在制定选项的过程中,选择落在使用友晶DE10-纳米开发板的基础上,旋风V FPGA。





自己的互动模式



为什么FPGA这么酷?



使用FPGA的主要优点:



  • . DE10-Nano , , , . IDE, Verilog.
  • . DE10-Nano HSC-ADC-EVALC ($110 $698.28). DE10-Nano , .
  • . , .
  • . FPGA- (FPGA – field-programmable gate array – , ), ( ). rocketboards c .




...



在交互模型的设计过程中,决定基于GPIO(通用引脚)实现SPI接口,DE10-Nano提供了该接口的触点基础。基于FPGA的SPI控制器实现不应该引起任何特殊问题,因为涉及类似主题的材料很多。



但是,通过USB接口将FPGA连接到计算机的实现带来了困难。



DE10-Nano具有以下USB端口:



  • USB mini-B由FT232R芯片供电,实现UART与USB的连接。
  • USB mini-B由SMSC USB3300芯片控制,该芯片实现USB接口的物理层,并用于对FPGA进行编程。


这些端口的使用非常复杂,因为DE10-Nano通过所谓的HPS硬处理器系统与这些端口进行通信-HP Cylone V芯片的一部分,该芯片包含微处理器模块,ARM Cortex处理器,闪存控制器等。 HPS和FPGA之间的主要区别在于,HPS是不变结构的块,已针对特定功能进行了优化,并且没有其编程工具(因此很难使用)。



Cyclone V芯片的HPS和FPGA部件具有自己的引脚。这些引脚不能在HPS和FPGA之间自由共享。 HPS联系人由HPS中运行的软件配置。通过HPS或任何其他受支持的外部源使用FPGA配置映像对FPGA引脚进行编程。



为了组织Cyclone V芯片的可编程逻辑与这些端口的交互作用,有必要创建一个在HPS上运行的特殊Linux引导程序,并且有必要开发一个程序,该程序能够将信号从可用USB端口的控制器传输到FPGA的自由触点。



在目前的知识阶段,这个问题被认为是压倒性的,因此决定寻找另一种方法。但是,对于面临类似问题并决定解决该问题的人们,阅读有关可能解决方案的文章可能会很有用



有出口!



在彻底了解Internet之后,决定使用外部UART控制器。



外部UART控制器是基于FT232RL芯片的小板。该开发板具有用于与计算机通信的miniUSB-B连接器和用于与微控制器和设备通信的6针连接器。

控制器通过USB接口连接到PC,并通过GPIO触点座连接到DE10-Nano。





Waveshare的控制器本身(在项目中使用)



使用USB上的UART接口从PC传输数据实际上消除了处理复杂的多层USB协议设备的需要。从现在开始,通过USB接口进行交互不再是我们关注的问题,因为此任务已分配给预先安装在系统中或由用户独立安装的驱动程序。



除了电源线和地线以及数据发送和接收线外,板上还有一些引脚,分别标记为RTS和CTS。这些触点用于所谓的流控制-一种机制,旨在根据信号的状态来发出准备从主设备或从设备接收数据的信号。不需要使用这些行,因此,要禁用该机制,必须在计算机驱动程序的设置中指出未使用流控制(这通常是默认配置)。



连接到Windows PC时,将UART控制器检测为虚拟串行端口。因此,与PC交互方案的开发归结为创建具有与串行虚拟端口交互功能的软件,以及为FPGA开发项目,该项目实现了通过UART接口接收/发送数据。



外部UART控制器实际上是DE10-Nano上已经存在的控制器的绝对模拟,但是它的唯一优点是能够直接连接到FPGA的空闲引脚。这种设备的价格从5美元到10美元不等。



软件开发



一般信息



如前所述,用于PC的软件开发被简化为创建支持与虚拟串行端口进行信息交换的程序。在分析用于软件开发的可用软件工具时,选择使用的是使用RTXT库的Java 8th版编程语言。



Java是一种强类型的面向对象编程语言,具有许多关键功能。特别是,将用Java编程语言编写的程序转换为特殊的字节码,从而使它们可以在具有Java虚拟机实现的任何计算机体系结构上运行。



Java标准库不具有与虚拟串行端口进行交互的功能。这就是RTXT库的用途。 RTXT是根据免费软件许可发行的。该库使用与接口交互的系统实现,并提供用于使用串行端口进行解析,连接,读取和写入操作的类。有关此库的更多信息,请参见此处



旧的但可靠的内置Swing库用作开发用户界面的工具。由于具有更改主题的功能,Swing中的简单UI或多或少看起来并不难看



该程序本身非常简单,主要使用RTXT库的文档功能。



程序的主要功能



这是确定可用端口的方式:



    public String[] getPorts() {
        ports = CommPortIdentifier.getPortIdentifiers();
        while (ports.hasMoreElements()) {
            CommPortIdentifier curPort = (CommPortIdentifier) ports.nextElement();

            if (curPort.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                portMap.put(curPort.getName(), curPort);
            }
        }
        return portMap.keySet().toArray(new String[0]);
    }


连接到所选端口:



    public void connect() {
        String selectedPort = (String)gui.ports.getSelectedItem();
        selectedPortIdentifier = portMap.get(selectedPort);
        CommPort commPort;
        try{
            commPort = selectedPortIdentifier.open("UART controller", TIMEOUT);
            serialPort = (SerialPort)commPort;
            serialPort.setSerialPortParams(BAUD_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            gui.writeLog(selectedPort + " opened successfully.");
        }catch (PortInUseException e){
            gui.writeLogWithWarning(selectedPort + " is in use. (" + e.toString() + ")");
        }catch (Exception e){
            gui.writeLogWithWarning("Failed to open " + selectedPort + " (" + e.toString() + ")");
        }
    }


数据传输过程:



    public boolean writeData(byte[] bytes){
        boolean successfull = false;
        try {
            gui.writeLog("WRITING: " + HexBinUtil.stringFromByteArray(bytes));
            output.write(bytes);
            output.flush();
            successfull = true;
        }
        catch (Exception e) {
            gui.writeLogWithWarning("Failed to write data. (" + e.toString() + ")");
        }
        return successfull;
    }


接收数据:



    public void serialEvent(SerialPortEvent serialPortEvent) {
        if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                byte singleData = (byte)input.read();
                gui.writeLog("READING: " + HexBinUtil.stringFromByteArray(singleData));
            }
            catch (Exception e) {
                gui.writeLogWithWarning("Failed to read data. (" + e.toString() + ")");
            }
        }
    }


如前所述,通过将一些有效的8位值的写入命令传输到文档中描述的特定寄存器地址来控制DAC / ADC。要确定寄存器的当前状态,必须发送读取命令并指定请求的寄存器的地址。文档一样,提供完整的描述



UART数据传输



在研究AD9993-EBZ的过程中,发现在可用的12位寄存器地址空间中仅使用了8个数据位。另外,寄存器状态的发送值由8位描述。为了确定数据传输的类型(写/读),需要传输1个数据位。



由于当前对UART接口上消息最大大小的限制是8个数据位,因此决定在写过程中发送3个连续的8位消息,在读过程中发送2个消息。



第一个包裹将包含数据传输的类型,在整个包裹大小中重复。因此,只能有两个可能的值:读时为00000000,写时为11111111。使用整数突发来传输一个数据位是为了简化对接收信号的进一步处理。

接下来,在记录过程中发送请求的寄存器的地址和寄存器状态的发送值。





开发的UART封装的波形图



用户界面







软件用户界面的主要元素是用于连接/断开可用串行端口的按钮(元素3,4),用于输入地址和寄存器值的字段(元素7,8),日志窗口(元素6)。该软件设计为在两种状态下与其交互:“已连接到端口”和“已从端口断开连接”。状态决定了程序界面上某些元素的活动,并且还限制了执行某些方法的能力,以减少出错和错误使用软件的可能性。启用后,程序处于“与端口断开连接”状态。另外,为了简化程序的使用(这是我的主要目标之一),添加了使用已保存的JSON格式命令连接文件的功能(元素10)。



命令加载过程:





文件选择





命令界面此



功能允许您将加载的命令分为几部分(元素12),自定义使用连接命令的过程(是否在按下命令时立即将命令发送到串行端口,或者根据所选命令填写地址字段和值) ...



开发FPGA项目



一般信息



在开始为FPGA开发项目之前,您需要确定他必须解决的任务。



听起来像是这样:FPGA项目必须支持以下数据转换:数据转换









DE10-Nano从UART接口的Tx线接收信号(上部信号)。接下来,FPGA需要从每个8位的三个消息中正确确定接收到的数据,并将它们转换为与文档相对应的SPI消息格式(以4行显示)。



实现此转换所需的主要模块是UART控制器模块和SPI控制器模块。本章的其余部分分配给他们。



在为FPGA开发项目时,使用了IDE Qartus Prime Lite Edition第17版。

如果您没有使用Quartus的经验,或者根本没有编程过FPGA,那么建议从Quartus上第一个项目的可理解(我认为)示例开始。



我想指出的是,下面描述的Verilog代码的所有摘录都是Internet上解决方案的汇编,它们并不具有任何独创性。同样,该项目的主要目标是解决特定问题。



UART控制器



描述



UART控制器包含三个模块:



  • 脉冲发生器
  • 录音模块;
  • 阅读模块。


建议查看这篇文章该文章摘录了大部分信息。此外,我将仅关注最重要的(在我看来)实施细节。



脉冲发生器



由于UART接口是异步的,因此接收器需要生成自己的参考信号以正确接收发送的信号,从而使其能够正确确定新信息位的开始。



标准UART波特率的范围通常为:300;600; 1200; 2400; 4800; 9600;19200; 38400;57600;115200;230400;460800; 921600波特 在我们的情况下,数据传输的波特率为9600。接下来,我们需要获得一个频率为符号率16倍的发生器。为了正确检测发射信号的电平,这是必需的。



为了产生脉冲,芯片上使用了50 MHz发生器。为了获得所需的频率,需要考虑发生器的第325个脉冲。

这是在Verilog中的外观:



input           Clk;                   //   50
input           Rst_n;               //    
input [15:0]    BaudRate;      //   ,  325
output          Tick;                //  
reg [15:0]      baudRateReg; // 

always @(posedge Clk or negedge Rst_n)
    if (!Rst_n) baudRateReg <= 16'b1;
    else if (Tick) baudRateReg <= 16'b1;
         else baudRateReg <= baudRateReg + 1'b1;
assign Tick = (baudRateReg == BaudRate);
endmodule


读卡器模块



读取器将来自RX线的输入信号转换为输出8位数据阵列。



直接读取并将读取的数据传输到输出:



input Clk, Rx,Tick;  //   50,  Rx,   
input [3:0]NBits;                  //     ,  8
output RxDone;	         //     
output [7:0]RxData;                         //  

reg  read_enable = 1'b0;                   //   
reg  RxDone = 1'b0;                         //   
reg [3:0] counter = 4'b0000;            //   
reg  start_bit = 1'b1;	                      //     
reg [4:0]Bit = 5'b00000;                  //    
reg [7:0] RxData;                            //    
reg [7:0] Read_data= 8'b00000000; //    


always @ (posedge Tick)  //        
	begin
	if (read_enable)
	begin
	RxDone <= 1'b0;			//   
	counter <= counter+1'b1;		// 
	

	if ((counter == 4'b1000) & (start_bit))	//   
	begin
	start_bit <= 1'b0;
	counter <= 4'b0000;
	end

	if ((counter == 4'b1111) & (!start_bit) & (Bit < NBits)) //  
	begin
	Bit <= Bit+1'b1;
	Read_data <= {Rx,Read_data[7:1]};
	counter <= 4'b0000;
	end
	
	if ((counter == 4'b1111) & (Bit == NBits)  & (Rx))  //  
	begin
	Bit <= 4'b0000;
	RxDone <= 1'b1;          //      
	counter <= 4'b0000;          //  
	start_bit <= 1'b1;		//   
	end
	end
	
end


always @ (posedge Clk)
begin

if (NBits == 4'b1000)            //  8  ,    
begin
RxData[7:0] <= Read_data[7:0];	
end

end


传输模块





传输模块将8位输入信号转换为UART串行数据包。



直接数据传输:



input Clk, Rst_n, TxEn;  // 50,  ,   
input Tick;                    //  
input [3:0]NBits;          //   
input [7:0]TxData;	

output Tx;
output TxDone;

reg  Tx;	
reg  TxDone = 1'b0;	
reg write_enable = 1'b0;
reg start_bit = 1'b1;	
reg stop_bit = 1'b0;	
reg [4:0] Bit = 5'b00000;	
reg [3:0] counter = 4'b0000;
reg [7:0] in_data=8'b00000000;

always @ (posedge Tick)  //        
begin

	if (!write_enable)	
	begin
	TxDone = 1'b0;
	start_bit <=1'b1;
	stop_bit <= 1'b0;
	end

	if (write_enable)
	begin
	counter <= counter+1'b1;	// 
	
	if(start_bit & !stop_bit)//        
	begin
	Tx <=1'b0;					
	in_data <= TxData;	

	if ((counter == 4'b1111) & (start_bit) )    //   
	begin		
	start_bit <= 1'b0;
	in_data <= {1'b0,in_data[7:1]};
	Tx <= in_data[0];
	end

	if ((counter == 4'b1111) & (!start_bit) &  (Bit < NBits-1))	//  
	begin		
	in_data <= {1'b0,in_data[7:1]};
	Bit<=Bit+1'b1;
	Tx <= in_data[0];
	start_bit <= 1'b0;
	counter <= 4'b0000;
	end	

	if ((counter == 4'b1111) & (Bit == NBits-1) & (!stop_bit))	//  
	begin
	Tx <= 1'b1;	
	counter <= 4'b0000;	
	stop_bit<=1'b1;
	end

	if ((counter == 4'b1111) & (Bit == NBits-1) & (stop_bit) )	// 
	begin
	Bit <= 4'b0000;
	TxDone <= 1'b1;
	counter <= 4'b0000;
	//start_bit <=1'b1;
	end
	
	end
		
end


SPI控制器



重要题外话



由于基于FPGA的SPI控制器比UART控制器具有更复杂的逻辑结构,因此对操作逻辑的进一步说明更易于在控制器的电路模型上进行。



控制器总体方案







开发的模型可以分为3个主要模块:



  • 顺序写模块;
  • 位计数器模块;
  • 错误分析器模块。


划分模块相当随意,因为电路在所使用的元件之间具有高度的连通性。该划分基于总图中显示的各个元素组执行的任务。



该电路的时钟由通过CLK_125线提供的12.5 MHz信号提供。



通过“ START”信号启动控制器在形成控制消息时的工作。通过该信号,电路的所有模块均被设置为初始状态,并且初始化了在SPI接口的输出线CLK,SS,MOSI上生成所需信号的周期的开始



顺序写模块







串行写模块将执行SPI控制器的主要任务,即将并行位数据输出到串行MOSI线。这归因于RG_24_PI_SO元素,该元素根据基于D触发器的移位寄存器的原理进行操作。



RG_24_PI_SO元素具有24个数据输入,对应于SPI发送格式上的AD9993-EBZ文档。它们包括:



  • 命令数据(DATA_0 – DATA_7);
  • 寄存器地址数据(ADR_0 – ADR_12);
  • W / R写入/读取模式位。


所显示的信号以逻辑电平“ 1”并行写入LoadP_ShiftN输入。此外,在LoadP_ShiftN输入处的逻辑电平“ 0”处,在CLK输入处的每个时钟周期,该元件交替地将记录的数据再现到MOSI输出的串行线。



位计数器模块







需要位计数器模块来确定SPI接口的SS线上的数据写使能信号的持续时间。根据AD9993-EBZ文档,由于使能信号的持续时间必须等于所传输数据的总持续时间,因此有必要从数据传输开始就对24个同步脉冲进行计数以确定所需的使能信号的持续时间。计数功能由ST_32元件执行,当检测到第24个时钟信号时,ST_32元件将再现一个信号,该信号用于重置计数器以及结束发送的使能信号。



除主要功能外,位计数器模块还负责初始化错误分析过程,该过程的初始动作是将读取值命令发送到最后记录的寄存器的地址。由于错误分析过程必须在等于从发送最后一个发送的数据位开始(实验建立)的那一刻起的23个同步脉冲的持续时间之后的时间间隔内开始,因此复位信号后的位计数器将切换到23个同步脉冲计数模式,从而确保了错误分析过程的操作。



错误分析模块







如前一个模块的说明中所述,为了提供错误分析功能,开发了一种方法,该方法基于在数据记录过程中使用的寄存器地址处读取存储在IC上的命令的值。读取过程对于将写入值与读取数据进行比较是必要的,以识别不一致之处,从而确定已发生的错误。误差分析模块基于RG_8_SI_PO元素,该元素根据移位寄存器原理工作。该元件将通过MISO串行端口接收的信号转换为并行的8位输出。然后,将数据与数据记录过程中使用的命令值进行比较。比较功能由CMP_8元素基于异或逻辑执行。如果发现差异,模块将向LED输出发送信号,该信号将处于逻辑单元状态,直到下一个数据记录过程为止。假定LED输出将连接到LED中的一个,DE10 Nano开发板上存在一组LED,这些LED将可视地指示已发生的错误。



结论



解决此问题的结果是,设计了PC和DAC / ADC器件之间的交互方案,并在物理上实现了许多关键优势。在实施过程中,解决了FPGA与PC的连接问题。解决方案是使用外部UART模块。PC软件是用Java编写的。该软件具有一个接口,该接口具有以开发的UART发送格式发送和接收数据的基本功能,此外,它还具有加载保存的命令的功能。开发了基于FPGA的UART和SPI控制器。



在该项目的框架内考虑的问题包括:



  • 评估集成电路与外部设备的交互方式;
  • 评估将FPGA用作匹配设备,数据交换缓冲区的方式;
  • 探索开发实用软件的最有效方法之一。


PS我将很高兴对错误有任何补充,说明和指示。



All Articles