我们在LabVIEW中编写FPGA加载器。 第二部分

通过USB将配置下载到FPGA或拆卸FTDI MPSSE
我们在LabVIEW中编写FPGA加载器。 第一部分




在第一篇文章中,我们测试了旧版本C上的加载算法,在第二篇文章中,我们了解了如何在LabVIEW中组织程序并实现简单的用户界面。 这次,我们将熟悉LabVIEW中的新工作方法,分析错误处理的功能并完成项目:我们实现了将配置文件加载到FPGA中的协议。

错误处理


打开源代码,分析函数MPSSE_open。 尽管算法简单(函数被称为另一个函数),但仍需要导入许多D2XX API元素: FT_OpenExFT_ResetDeviceFT_PurgeFT_SetUSBParametersFT_SetCharsFT_SetTimeoutsFT_SetLatencyTimerFT_SetFlowControlFT_SetBitMode前一篇文章所示,使用“ Call library Function节点执行函数的导入。 该节点具有用于错误控制的专用端子。 LabVIEW有一个简单的规则:所有VI必须跟踪错误并报告错误终端返回的错误。 大多数内置VI都严格遵循它。 我希望每个人都知道控制和处理错误的重要性,尤其是在调试阶段,但这是另一个重要原因,为什么它对“经典”程序员不那么重要。 LabVIEW在程序框图中没有严格的设备顺序:当输入中的数据准备就绪时,将执行设备。 如果将一个VI的输出中的数据传输到另一个VI的输入中,则很显然第一个VI会在开始时起作用,而第二个VI才起作用。 但是,如果不进行数据传输,并且VI执行独立的操作,该怎么办? 当然,您可以使用繁琐的“平面序列结构”,但是通过一系列错误将设备彼此连接起来会更加方便。


导入D2XX函数时,我们会遇到两种类型的错误。 第一个-这是直接导入错误-返回Call library Function块本身。 第二个错误是库本身的错误;几乎每个函数都通过FT_STATUS返回该错误。 头文件ftd2xx.h中将所有可能的值都描述为枚举。 尽管足以知道FT_OK值是没有错误,而所有其他值都是错误代码,但我不仅要跟踪错误本身的事实,而且还要跟踪发生了什么错误以及确切的位置。


在LabVIEW中,错误数据通过error簇传播。 这是一种特殊的专用数据类型; LabVIEW具有许多VI和用于处理它的函数。 错误群集由三个元素组成:逻辑变量-显示状态,带符号的整数-错误代码,字符串-错误源。 该状态指示是否发生了错误,错误代码确定了错误的类型,并由特殊VI用来生成报告。 该行给出了错误发生的确切位置的更详细的想法。 LabVIEW接受到,如果状态为TRUE ,则为错误;如果状态为FALSE ,但代码不为零,并且描述行不为空,则为警告 ;如果状态为FALSE ,则代码为零,且行为空-无错误。




LabVIEW包含一个内部数据库,每个错误代码均与其说明相关联。 对于每种类型的错误,都会分配特殊范围的代码值。 例如,对于与网络运行相关的错误,分配了几个范围:–2147467263至–1967390460、61至65、116至118和122、1101、1114、1115、1132至1134、1139至1143和1178至1185为用户定义的错误保留了两个范围,分别是–8999至–8000和5000至9999。从这些范围中,我们可以为D2XX库的错误代码选择值。


我们创建一个VI,该VI接收D2XX函数的状态作为输入,并将该状态转换为LabVIEW错误簇。 LabVIEW中的大多数函数和VI在“ Error In输入”输入中处于“ TRUE状态,不执行其代码,而是将错误信息传输至“ Error Out终端。 这使您可以通过整个链有效地将有关源的信息传输到错误处理程序,从而避免了在紧急模式下执行代码。 希望我们的VI具有相似的行为。


让我们以enum的形式排列D2XX状态列表,并将其放在单独的类型中(在上一篇文章中,我们使用FTDI类型进行了此操作)。


枚举FT_Status

我们将新VI保存为FT_error.vi。 我们将两个群集“ Error In和“ Error Out前面板,您可以在“数组,矩阵和群集”面板中找到它们。 如上一篇文章所述,我们将它们分别连接到左下角和右下角的连接面板上的端子,这是LabVIEW采用的错误流端子的位置。 我们将Case结构添加到框图,将Error In群集提交到Case selector输入,之后Case结构更改颜色并划分两个子图:“无错误”-绿色和“错误”-红色。 在“错误”情况下,我们将错误簇从选择器终端直接传输到右边界的输出隧道。 在绿色案例中,我们根据状态添加另一个Case ,它将确定是创建错误(状态不等于FT_OK)还是保持原样:跳过输入错误集群以退出而不更改。


为了将错误代码从技术上转换为群集,可以使用VI Error Cluster From Error Code VI 。 该子VI在错误描述中添加了一个调用链,因此我们不仅可以确定发生了什么 ,还可以确定发生在哪里


要选择与输入状态(FT_Status)相对应的文本,请使用属性块:选择“ RingText.Text”。 错误文本Error Cluster From Error Code VI发送到Error Cluster From Error Code VIerror message输入。
不要忘了画一个“会说话的”图标。


FT_error.vi


前(前)子仪器面板



方框图。 输入错误



方框图。 输入没有错误,状态为FT_OK



方框图。 输入没有错误,但状态与FT_OK不同



要测试FT_error,可以创建一个空的VI,在其中添加创建的VI,并查看在应用各种状态时启动时值将如何变化。


FT_error.vi测试


设备的前(前)面板



方块图


现在,在从D2XX API调用任何函数之后,我们将使用SubVI FT_error.vi。 在整个调用层次结构中,所有VI都会传递错误簇。


在顶级VI中,我们必须决定如何处理检测到的错误:您可以在对话框中显示消息,将其写入报告文件,忽略它,或者简单地“安静地”结束应用程序。 对话框是报告错误的最简单,最流行的方法。 对于新手程序员而言,这也很方便,因为它无关紧要。 在每个VI中,默认情况下均启用了自动错误处理模式(位于VI Properties菜单的Execution类别中的Enable auto error processing )。 它的工作原理是:如果某个节点的Error Out输出端子未连接到任何地方,并且此节点发生错误,则LabVIEW将暂停应用程序并显示一个对话框。 如果连接了节点的“ Error Out终端,则错误流将按编程方式传播,并且不会发生其他操作。 但是,可以通过编程方式调用消息窗口,为此,您需要使用General Error Handler Simple Error Handler程序VI和Simple Error Handler程序VI(位于“对话框和用户界面”面板中)。 在这种情况下,我们可以使用错误信息来完成程序。 在框图中,它看起来像这样:



可点击的图片


发生错误时,程序将被挂起,将显示一个报告窗口,关闭该窗口后,程序将正确退出。


报告窗口


打开和关闭FTDI


因此,回到MPSSE_open函数。 创建一个新的VI 。 首先,添加错误流的端子。 添加选择结构,然后Error In选择器上选择“ Error In输入”输入。 在绿色情况下,我们按照Sishny原型中的顺序和参数导入函数。 Call Library Function Node所有节点通过错误流成链状连接。 在通过隧道的红色情况下,我们将Error InError In的输出端子连接。



可点击的图片



VI MPSSE_open.vi


带有FTDI描述的行( Description )被发送到SubVI的输入,在输出处Handle和处于MPSSE模式的已初始化FTDI芯片。


让我们创建一个完成FTDI工作的VP,您已经可以检查硬件的性能了。


FT_Close.vi


方块图



前面板


在上一篇文章中,为了调试接口,我们制作了VI存根SP_FT_MPSSE_FPGA.vi,现在该填充它了。 将MPSSE_open.vi和FT_Close.vi添加到其框图。 在此阶段,很难评估初始化是否正确,但是,MPSSE_open.vi输出上的Handle的非零值以及没有错误将告诉我们很多。



流程图SP_FT_MPSSE_FPGA.vi


为了查看Handle的值Handle可以使用“ Probe Watch Window”。 这是一种方便的调试工具,可让您在设备执行期间在任何(几乎所有)线路上显示数据值。 为了在该行上设置样本,您需要在该行的上下文菜单中选择“探针”。 “ Probe Watch Window”窗口将打开,并且带有样品编号的数字将显示在该行上。 在上图中,它是“ 3”。


探针观察窗


在“句柄”行上,值698389336


太好了! 我们启动顶层VI,将调试板连接到计算机。 所连接的FTDI芯片的描述出现在“选择设备”列表中,单击“程序”按钮,然后...什么都没有发生。 仅在“ Probe Watch”窗口中,“ Handle ”值出现。 那很好。


我们关闭电路板,清除设备列表。 点击“程序”。 这是错误报告窗口弹出的地方。


报告窗口


单击“继续”按钮后,VI将完成其工作。


如果找不到任何设备,则禁止按下按钮。 我们修改案例“超时”事件处理程序。 让我提醒您,连接到PC的FTDI芯片每秒扫描两次,如果它们被检测到并可用于对FPGA进行编程,则它们的描述符通过Strings[]属性添加到Devices list 。 我们为“编程”创建Disabled属性,如果找不到合适的设备,请关闭按钮并使其变暗。


案例超时


可点击的图片


掌握GPIO


激活MPSSE后,将通过所谓的“操作码”进行操作,并且FT_Write API函数仅使用FT_WriteFT_ReadFT_Queue (以查找接收器缓冲区的状态)。 我们沿着创建的轨迹创建相应的VI:FT_Write.vi,FT_Read.vi,FT_Queue.vi。


有点常规


FT_Write.vi



方框图。 FT_Write.vi



FT_Read.vi



方框图。 FT_Read.vi



FT_Queue.vi



方框图。 FT_Queue.vi


现在,从这三个积木中,我们布置VI来读取并写入并行端口。 该值方便地表示为布尔变量数组。


MPSSE_Set_LByte.vi和MPSSE_Get_LByte.vi


MPSSE_Set_LByte.vi



方框图。 MPSSE_Set_LByte.vi



MPSSE_Get_LByte.vi



方框图。 MPSSE_Get_LByte.vi


我承认我很懒惰为所有操作码创建一个命名列表,所以我以魔术数字的形式将它们保留了下来。


如第一篇文章所述,无源串行FPGA启动协议仅是带有附加标志操作的SPI。 总共使用了五个分支 :必须将DCLKDATA [0]nCONFIG行配置为输出,将nSTATUSCONF_DONE行配置为输入。


表格布局引脚
FPGA引脚引脚名称销钉MPSSE方向默认值
时钟BDBUS038TCK / SK0
数据[0]BDBUS139TDI /溶解氧1个
配置文件BDBUS240TDO / DI1个
状态BDBUS341TMS / CS1个
CONF_DONEBDBUS443GPIOL01个

我们需要一个VP,它可以在不影响所有其他支路的情况下更改所选支路的值。 首先,使用端口中分支的序列号创建Enum ,将其另存为“ Strict Type Def”到文件SP_LBYTE_BITS.ctl。 我们创建一个新的VI,添加熟悉的错误流程终端。 我们使用MPSSE_Get_LByte.vi读取并行端口的当前值,使用“ Replace Array Subset功能修改所需的位并将该值写回到端口(MPSSE_Set_LByte.vi)。


SP_Set_Flag.vi


SP_Set_Flag.vi



方框图。 SP_Set_Flag.vi



枚举SP_LBYTE_BITS.ctl


要开始配置,MPSSE必须在nCONFIG线上产生从低到高的变。 一旦FPGA准备好接收数据,它将在nSTATUS线上形成高电平。 在这个阶段,一切准备就绪,可以用铁进行实验了。 在框图SP_FT_MPSSE_FPGA.v上,我们添加了控制线nCONFIG-在MPSSE初始化之后,我们给出了一个低电平,然后为高电平。 每次操作(用于调试)后,我们都会读取端口支脚的状态。


SP_FT_MPSSE_FPGA.vi


启动期间



方块图


通常,在启动VI时,很明显FPGA响应nCONFIG线上的转换-在nSTATUS引脚上设置为0,然后再设置为1。 但是用示波器来监视它并不是多余的。 几乎任何带有触发触发(待机)的两通道示波器都适用。 我将通道A (蓝色轨道)放入电路nCONFIG的控制点中,通道B (红色轨道)-链nSTATUS 。 触发器设置为通道A的下降沿



图片是可单击的。 随着细节!


处理文件


FPGA准备接受配置文件。 我们准备好将文件传输到FPGA了吗?


LabVIEW包含大量用于处理文件的工具。 我不能说该功能足以满足所有任务,但是,诸如读取写入之类的基本操作可以轻松愉快地执行。 可在“文件I / O”面板中找到用于处理文件的基本VI集。 为了解决该问题,您需要打开配置文件,评估其大小(我们需要知道发送FPGA的字节数),然后读取并关闭它。 一切都很简单,一个接一个。 我们使用Open/Create/Replace FileGet File SizeRead from Binary FileClose File refnum ,将它们与错误流链和refnum结合使用-打开文件时会创建一个数字,例如文件描述符,应将其传送至其他可处理VI的输入该文件。


到目前为止,我们没有地方可以处理读取的数据,但是,如果您确实要检查链的可操作性,则可以创建String类型的指示器并进行一些设置。 在上下文菜单中,激活“十六进制显示”选项,打开垂直滚动条(“可见项->垂直滚动条”),启动后,我们观察二进制配置文件的内容。


SP_FT_MPSSE_FPGA.vi


前面板 我们看一下文件的内容



方框图。 Karinka可点击


在VI的框图上形成的两条独立的并行代码行,因此使用了独立的错误链。 为了减少流入一个Error Out终端的并行流,使用了“ Merge Errors功能。 此函数从上到下查找输入错误(是的,可以有两个以上的输入端子,用鼠标拉伸),然后返回找到的第一个错误。 如果没有错误,它将返回第一条警告消息。 如果没有警告,则输出无错误。 重要的是要注意,“ Merge Errors输入的连接顺序确定了Merge Errors的优先级,如果在两个链中立即发生错误,则较低的错误将被忽略。 这应该小心对待。


如果我们尝试在不选择文件的情况下在顶级VI中按下“程序”按钮,则输入SP_FT_MPSSE_FPGA.vi将收到一个空路径,这将导致错误“错误1430。LabVIEW:(Hex 0x596)路径为空或相对。您必须使用绝对路径。” 就像我儿时的朋友说的那样:“步枪,这是世间万物!” 这个错误根本不是错误,而是用户的疏忽。 我们不会停止该程序并使用带有红叉的窗口发誓,我们只是从流中删除此代码的错误,并在对话框中建议用户决定该文件。 要过滤错误,请使用“对话框和用户界面”选板中的“清除错误” VI。 要显示消息-“一个按钮对话框”。



方块图


可点击的图片


下载配置


对于串行数据传输,MPSSE处理器需要发送操作码0x18,命令参数将是传输序列的长度(两个字节,从最低的字节开始),以及数据序列本身。 长度编码为负一。 让我们以VI MPSSE_send的形式发送数据块。


MPSSE_Send.vi


MPSSE_Send.vi



方块图


输入缓冲区的大小( Array Size )转换为双字节类型U16 ,我们减去一个,交换低字节和高字节( Swap Bytes )-您需要从最低字节开始发送长度,并将双字节数字转换为单字节数组( Type Cast )。


Type Cast功能值得特别注意。 这是一种通用类型的转换器,其独创性有时非常令人惊讶。 简而言之,则:



直观地为程序员


但是,这不仅是将数据转换为其他类型,还是一种启发式的解释。 该功能使您可以在不兼容的数据类型之间执行转换,而该功能则毫不犹豫地对齐输入数据,甚至删除了“多余的”部分。 如果请求的数据类型比输入数据需要更多的内存,则该函数将分配丢失的数量。 对于新手开发人员来说,LabVIEW Type Cast可以成为救生员,但是随着年龄的增长,最好不要使用这样的转换器-它非常隐蔽,可能会导致意外错误。 最好使用更明确的转换方法,例如Coerce To Type


初始化MPSSE处理器时,我们将用于数据传输的缓冲区的最大允许大小设置为65536字节,因此我们必须将配置文件划分为大小不超过指定大小的片段。 我们将使用Array Subset函数,该函数从数组中选择一个以index元素和long length开头的子数组。 我们将在While循环中将其断开,将索引的每次迭代增加65536,在迭代之间,我们将值传递给移位寄存器。 一旦无法从主阵列中捏入65536个字节,我们将处理剩下的所有内容,将其发送并停止循环。


根据下载协议,在传输完所有数据之后,必须再施加两个时钟脉冲以启动FPGA初始化。 为此,在循环之后,我们发送另一个“空”字节。


SP_FT_MPSSE_FPGA.vi


可点击的图片


为了理解固件的成功,我们考虑了这些标志,如果将CONF_DONE设置为1,则报告顶层VI一切正常。


程序完成。 仍然需要确保FPGA成功闪烁,并且板上的LED会愉快地闪烁。


关于VP命名


, , LabVIEW, , SubVI. . :


  • — , FTDI, API D2XX. "FT", FT_Close.vi FT_Read.vi.
  • — MPSSE. "MPSSE". : MPSSE_open.vi, MPSSE_Set_LByte.vi, MPSSE_Get_LByte.vi.
  • — "Passive Serial" MPSSE. "S". , SP_FT_MPSSE_FPGA.vi ( , ) SP_LBYTE_BITS.ctl.
  • . . , .

( ), . subVI .


结论


, , .



, LabVIEW, . , , , ( ). .



  1. . LabVIEW: . . . . .– .:
    , 2008 – 400 .: .
  2. labview_mpsse . .
  3. .
  4. Software Application Development D2XX Programmer's Guide . API D2XX.

Source: https://habr.com/ru/post/zh-CN429448/


All Articles