This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] LMX2572EVM:使用 USB2ANY.dll 版本2.7.0通过 Reference PRO 进行编程

Guru**** 2380860 points
Other Parts Discussed in Thread: LMX2572EVM, LMX2572, USB2ANY
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/clock-timing-group/clock-and-timing/f/clock-timing-forum/1120349/lmx2572evm-programming-with-the-reference-pro-using-usb2any-dll-version-2-7-0

器件型号:LMX2572EVM
Thread 中讨论的其他器件: LMX2572USB2ANY

您好!  

我目前正在尝试通过 python 脚本对 LMX2572EVM 板进行自动化编程。

我从这里获得了 DLL 文件:SDK链接

到目前为止、我可以使用脚本执行这些操作:  

  1. 检测器件
  2. 检索其序列号
  3. 指定为 U2A_Handle
  4. 将十六进制值写入具有给定成功写入字节的寄存器

即使在写入过程中不返回错误代码、也不会更改 LMX2572板的输出。 它会在我使用时执行该操作

TICS Pro 程序来写入寄存器。  

我认为必须这样做、因为我没有 正确设置用于写入的 u2aSPI_Control 参数。 我无法通过数据表或检索任何信息

我不小心错过了它...

为了写入电路板、此函数是否有任何默认设置?

您好!  

Dave

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Dave、

    您能否分享您的代码供审核?

    上面的 SDK 链接有一个 API 手册、其中介绍了所有 SPI 函数在 USB2ANY 中的工作原理-有关 u2aSPI_Control 参数的其他信息、请参阅此手册; 作为参考、我们使用 CPOL=1 (无效状态高电平)、CPHA=0 (在后沿捕获)、CS 极性低电平有效、每个数据包之后的 CS (对于 USB2ANY < v2.9.1.1)、8位 SPI、MSB 第一位方向和 API 手册中针对各种可用频率指定的标准分频器值。

    对于 LMX2572、RESET 位应切换一次、然后 TICS Pro 中的所有寄存器应按降序写入、最高地址写入最低地址。 R0应该被写入 FCAL_EN=1。 最后一次写入应在 写入 R0之前等待10ms、以便在寄存器编程在电源引脚上引入大电流瞬变后使内部 LDO 有机会稳定。

    此致、

    Derek Payne

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的回复 Derek!

    我调整了我的代码、并采取了几个步骤、简单地查看我是否可以将复位写入这些器件。

    但它仍然为我提供了一个返回代码 No error、而器件没有发生任何变化。 我将其连接到示波器上并使用外部电源来物理检查器件设置是否发生变化。 直到现在还没有运气……

    代码如下:

    import time
    
    import ctypes
    
    def getStatus(code):
        """
        Translate status code to readable text.
        """
        textBuff = ctypes.create_string_buffer(40)
        U2A.u2aStatus_GetText(code, textBuff, 40)
        status = ""
        for char in textBuff:
            status += char.decode("utf-8")
            if char == b'\x00':
                    break
        if code >= 0:
            return status
        print(f"Error: {status}")
        exit(1)
    
    U2A = ctypes.WinDLL(r"./USB2ANY.dll")
    
    SPI_ClockPhase=0        #SPI_Capture_On_Trailing_Edge 
    SPI_ClockPolarity=0     #SPI_Inactive_State_Low
    SPI_BitDirection=1      #SPI_MSB_First
    SPI_CharacterLength=0   #SPI__8_Bit
    SPI_CSType=1            #SPI_With_Every_Packet
    SPI_CSPolarity=0        #SPI_Active_High
    DividerHigh=0
    DividerLow=3           #8000 kbps
    
    NDEVS = U2A.u2aFindControllers()   
    print(f"Amount found devices: {NDEVS}") #check how many devices available.
    
    for dev in range(NDEVS):
        SERIALNUMBER_BUFFER = ctypes.create_string_buffer(40)
        if U2A.u2aGetSerialNumber(dev, SERIALNUMBER_BUFFER) == 0: 
            SERIALNUMBER= ""
            for s in SERIALNUMBER_BUFFER:
                SERIALNUMBER+=s.decode("utf-8")
                if s == b'\x00':
                    break
    
            U2A_HANDLE = U2A.u2aOpen(SERIALNUMBER_BUFFER)
            statusCode = U2A.u2aSPI_Control(
                U2A_HANDLE,
                SPI_ClockPhase,
                SPI_ClockPolarity,
                SPI_BitDirection,
                SPI_CharacterLength,
                SPI_CSType,
                SPI_CSPolarity,
                DividerHigh, 
                DividerLow)
    
            print("Status from u2aSPI_Control: ", getStatus(statusCode))
    
            resetVal = 2
            FCALVal = 4
            RESET = resetVal.to_bytes(3, 'big')
            FCAL_EN = FCALVal.to_bytes(3, 'big')
            print(RESET, FCAL_EN)
            U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3, RESET) #toggle reset bit once before writing..
            time.sleep(0.01) #sleep 10ms before writing FCAL_EN=1
            U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3, FCAL_EN) 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢 Dave。

    应使用 SPI_CSPolarity=1 (SPI_Active_Low)。

    根据写入 RESET 和 FCAL_EN 的方式、您可能会混淆字段和寄存器。 在寄存器映射中、每个寄存 器都有一个地址(三字节写入序列中的第一个字节)和一组数据值(映射到该寄存器地址的字段)。  单个寄存器地址中的所有字段都必须并行写入、包括示例代码中可能未按需要写入的其他字段(MUXOUT_LD_SEL、位4和13中的强制值1、FCAL_LPFD_ADJ 和 FCAL_HPFD_ADJ、OUT_MUTE、VCO_PHASE_SYNC_EN、RAMP_EN、RAM_EN、 ADD_HOLD)。

    字段和寄存器关系的更通用定义可能与下面的代码类似。 这不一定是我认可使用的代码-它更能说明字段/寄存器的关系。 尽管如此、如果  用户希望直接使用器件、可以积极地解析 C:\ProgramData\Texas Instruments\TICS Pro 器件目录中的器件 INI 文件、但这超出了我将为 E2E 响应生成的示例代码的范围。

    class Field:
        def __init__(self, val, width):
            if width < 1:
                raise ValueError("width must be > 1")
            self.width = width
            if val >= 1<<width:
                raise ValueError(f"{val} larger than {width}-bit field width")
            self._val = val
            
        @property
        def val(self):
            return self._val
            
        @val.setter
        def val(self, value):
            if value < 0 or value >= (1<<self.width)-1:
                raise ValueError(f"{value} larger than {self.width}-bit field width")
            self._val = value
        
    class Register:
        def __init__(self, address, address_offset=16, width=24, endian='big'):
            self.address = address
            self.address_offset = address_offset
            self._addrbits = address << address_offset
            self._datamask = (1<<address_offset)-1
            self.fields = []
            self.width = width
            self._bytes = (width+7)>>3
            self.endian = endian
        
        def add_field(self, field, offset, lsb=0):
            self.fields.append({
                'field' : field,
                'offset': offset,
                'lsb'   : lsb
            })
        
        @property
        def val(self):
            value = self._addrbits
            for f in self.fields:
                value |= ((f['field'].val>>f['lsb'])<<f['offset'])&self._datamask
            return value
    
        @property
        def bytes(self):
            return self.val.to_bytes(self._bytes, self.endian)
            
    # example: R0
    RAMP_EN = Field(0, 1)
    VCO_PHASE_SYNC_EN = Field(0, 1)
    _R0_13_12_RSVD = Field(2, 2)
    ADD_HOLD = Field(0, 1)
    _R0_10_RSVD = Field(0, 1)
    OUT_MUTE = Field(1, 1)
    FCAL_HPFD_ADJ = Field(0, 2)
    FCAL_LPFD_ADJ = Field(0, 2)
    _R0_4_RSVD = Field(1, 1)
    FCAL_EN = Field(1, 1)
    MUXOUT_LD_SEL = Field(1, 1)
    RESET = Field(0, 1)
    POWERDOWN = Field(0, 1)
    R0 = Register(0)
    R0.add_field(RAMP_EN, 15)
    R0.add_field(VCO_PHASE_SYNC_EN, 14)
    R0.add_field(_R0_13_12_RSVD, 12)
    R0.add_field(ADD_HOLD, 11)
    R0.add_field(_R0_10_RSVD, 10)
    R0.add_field(OUT_MUTE, 9)
    R0.add_field(FCAL_HPFD_ADJ, 7)
    R0.add_field(FCAL_LPFD_ADJ, 5)
    R0.add_field(_R0_4_RSVD, 4)
    R0.add_field(FCAL_EN, 3)
    R0.add_field(MUXOUT_LD_SEL, 2)
    R0.add_field(RESET, 1)
    R0.add_field(POWERDOWN, 0)
    
    print(R0.val) # should print 8732 (0x00221C)
    print(R0.bytes) # should print b'\x00"\x1c'
    #U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3, R0.bytes)
    
    # example 2: multi-byte field
    PLL_N = Field(0x28, 19)
    _R34_15_3_RSVD = Field(2, 13)
    R36 = Register(36)
    R34 = Register(34)
    R36.add_field(PLL_N, 0)
    R34.add_field(PLL_N, 0, lsb=16)
    R34.add_field(_R34_15_3_RSVD, 3)
    
    # demonstrating write works as expected
    PLL_N.val = 0x5BABE
    print(R34.val, R36.val) # should print 2228245 2407102 (0x220015, 0x24BABE)
    
    # example 3: converting HexRegisterFiles to writable byte arrays
    with open("HexRegisterValues.txt",'r') as f:
        lines = f.readlines()
    regmap = []
    for line in lines:
        regmap.append(int(line.split('\t')[1][2:], 16).to_bytes(3,'big'))
    
    # for reg in regmap:
    #     U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3, reg)

    为清楚起见、我不确定是否省略了更多编程、但 LMX2572确实需要对其他寄存器进行编程才能正常工作。 分频器、VCO 校准设置等的默认值 不可用-某些值必须编程为不同于默认值的值。 TICS Pro 工具可用于生成完整的十六进制寄存器值(File -> Export Hex Registers)、以便按 正确的顺序对所有字段进行编程。  十六进制寄存器值将在复位和 FCAL_EN 写入之间进行编程。 我在上面的代码中包含了一个示例、解释了 如何解析和写入十六进制寄存器值。

    此致、

    Derek Payne

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢 Derek!!!

    它工作正常、您很好地解释了字段和寄存器的工作原理。 我调节了我的代码、我认为初始错误实际上是在写入寄存器之前的第一次复位、而且似乎我只能写入一个器件、即使我给出了另一个句柄值。 有时、它甚至根本不会进行编程、并且会卡住、除非我首先使用 TICS Pro 应用程序对其进行编程。 我注意到、这些应用强制用户在编程前切换器件/接口、因此无法立即对所有连接的器件进行编程。 到目前为止、代码如下:  

    import ctypes
    import time
    class Register():
        def __init__(self, address) -> None:
            self.address = address
            self.regmap = {}
    
        def addField(self, bit, field, val):
            self.regmap[field] = {  "bit":bit,
                                    "val":val}
    
        def getValue(self):
            mask = self.address << 16
            for field in list(self.regmap.keys()):
                mask = mask | (self.regmap[field]["val"]<<self.regmap[field]["bit"])
    
            return mask
        def getByte(self):
            return self.getValue().to_bytes(3, 'big')
    
        def getHex(self):
            return hex(self.getValue())
    
    class U2ADEV():
        def __init__(self, filepath) -> None:
            self.U2A = ctypes.WinDLL(filepath)
            self.SNList = [] #Serial numbers from devices
    
        def getSerialNumbers(self):
            ndevs = self.U2A.u2aFindControllers()   
            for dev in range(ndevs):
                SERIALNUMBER_BUFFER = ctypes.create_string_buffer(40)
                if self.U2A.u2aGetSerialNumber(dev, SERIALNUMBER_BUFFER) == 0: 
                    for i,c in enumerate(SERIALNUMBER_BUFFER,0):
                        if c == b'\x00':
                            self.SNList.append(SERIALNUMBER_BUFFER[:i])
                            break                     
        
        def setupSPI(self, U2A_HANDLE):
            SPI_ClockPhase=0        #SPI_Capture_On_Trailing_Edge 
            SPI_ClockPolarity=0     #SPI_Inactive_State_Low
            SPI_BitDirection=1      #SPI_MSB_First
            SPI_CharacterLength=0   #SPI__8_Bit
            SPI_CSType=1            #SPI_With_Every_Packet
            SPI_CSPolarity=1        #SPI_Active_Low
            DividerHigh=0
            DividerLow=3
            self.U2A.u2aSPI_Control(U2A_HANDLE,
                                    SPI_ClockPhase,
                                    SPI_ClockPolarity,
                                    SPI_BitDirection,
                                    SPI_CharacterLength,
                                    SPI_CSType,
                                    SPI_CSPolarity,
                                    DividerHigh, 
                                    DividerLow)
    
        def getStatus(self,code):
            """
            Translate status code to readable text.
            """
            textBuff = ctypes.create_string_buffer(40)
            self.U2A.u2aStatus_GetText(code, textBuff, 40)
            status = ""
            for char in textBuff:
                status += char.decode("utf-8")
                if char == b'\x00':
                        break
            if code >= 0:
                return status
            print(f"Error: {status}")
    
        def writeHexFile(self,SERIAL, filePath):
            U2A_HANDLE = self.U2A.u2aOpen(SERIAL)
            if U2A_HANDLE < 0:
                self.getStatus(U2A_HANDLE)
                exit(1)
    
            print(f"Opened: {SERIAL.decode('utf-8')}")
            hexData = open(filePath, "r")
            for line in hexData.readlines():
                datamap = line.split('\t')
                address = datamap[0]
                strRegMap = datamap[1].rstrip()
                regMap = int(strRegMap, 16).to_bytes(3,'big')
                if address == "R0": #sleep 10ms before writing R0
                    time.sleep(0.01)
                ret = self.U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3, regMap)
                print(f"Serial: {SERIAL.decode('utf-8')}\tAddress: {address}\tregMap: {strRegMap}\tByteSuccess: {ret}")
            self.U2A.u2aClose(U2A_HANDLE)
            print(f"Closed: {SERIAL.decode('utf-8')}")
    
        def writeRegisterMap(self, SERIAL, regmap):
            U2A_HANDLE = self.U2A.u2aOpen(SERIAL)
            if U2A_HANDLE < 0:
                self.getStatus(U2A_HANDLE)
                exit(1)
    
            hexRegMap = regmap.hex()
            address = int.from_bytes(regmap[:1], 'big')
            
            print(f"Opened: {SERIAL.decode('utf-8')}")
            ret = self.U2A.u2aSPI_WriteAndRead(U2A_HANDLE, 3,regmap) 
            print(f"Serial: {SERIAL.decode('utf-8')}\tAddress: R{address}\tregMap: 0x{hexRegMap}\tByteSuccess: {ret}")
            self.U2A.u2aClose(U2A_HANDLE)
            print(f"Closed: {SERIAL.decode('utf-8')}")
    
    
    
    R0 = Register(0)
    R0.addField(15, "RAMP_EN", 0)
    R0.addField(14, "VCO_PHASE_SYNC_EN", 0)
    R0.addField(12, "_R0_13_12_RSVD", 2)
    R0.addField(11, "ADD_HOLD", 0)
    R0.addField(10, "_R0_10_RSVD", 0)
    R0.addField(9, "OUT_MUTE", 1)
    R0.addField(7, "FCAL_HPFD_ADJ", 0)
    R0.addField(5, "FCAL_LPFD_ADJ", 0)
    R0.addField(4,"_R0_4_RSVD", 1)
    R0.addField(3, "FCAL_EN", 1)
    R0.addField(2,"MUXOUT_LD_SEL", 1)
    R0.addField(1, "RESET", 1)
    R0.addField(0, "POWERDOWN", 0)
    R0_RESET = R0.getByte()
    
    # _R0 = Register(0)
    # _R0.addField(15, "RAMP_EN", 0)
    # _R0.addField(14, "VCO_PHASE_SYNC_EN", 0)
    # _R0.addField(12, "_R0_13_12_RSVD", 2)
    # _R0.addField(11, "ADD_HOLD", 0)
    # _R0.addField(10, "_R0_10_RSVD", 0)
    # _R0.addField(9, "OUT_MUTE", 1)
    # _R0.addField(7, "FCAL_HPFD_ADJ", 0)
    # _R0.addField(5, "FCAL_LPFD_ADJ", 0)
    # _R0.addField(4,"_R0_4_RSVD", 1)
    # _R0.addField(3, "FCAL_EN", 1)
    # _R0.addField(2,"MUXOUT_LD_SEL", 1)
    # _R0.addField(1, "RESET", 0)
    # _R0.addField(0, "POWERDOWN", 0)
    # R0_FCAL_EN = _R0.getByte()
    
    R44 = Register(44)
    R44.addField(14, "_R44_15_RSVD", 0)
    R44.addField(8, "OUTA_PWR", 50)
    R44.addField(7, "OUTB_PD", 1)
    R44.addField(6, "OUTA_PD", 0)
    R44.addField(5, "MASH_RESET_N", 1)
    R44.addField(3, "_R44_15_RSVD", 0)
    R44.addField(0, "MASH_ORDER", 3)
    R44_MAP = R44.getByte()
    
    U2A = U2ADEV(r"./USB2ANY.dll")
    U2A.getSerialNumbers()
    dev0 = U2A.SNList[1]
    U2A.writeRegisterMap(dev0, R0_RESET) #Reset before writing
    # U2A.writeRegisterMap(dev0, R44_MAP) #adjusting output power channel A
    U2A.writeHexFile(dev0, r"./HexRegisterValuesScope.txt")
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Dave、

    很高兴它在工作(至少比以前好)。

    TICS Pro 实际上并不包含同一总线上的多个器件的概念( 目前)。 另一方面、USB2ANY 应支持同一总线上的多个器件(只要使用 ReadAndWriteEx API 函数来区分芯片选择)或同时打开多个 USB2ANY 句柄(两个器件都需要初始化其 SPI 总线)。

    我建议将 ctypes.WinDLL 引用类属性而不是实例属性。 具有多个 DLL 包装程序实例也可能会导致一些奇怪的行为、但我对此不太可能。

    此致、

    Derek Payne

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    再次感谢 Derek!

    我换用了另一个电路板、看起来工作正常。 我注意到了

    u2aSPI_WriteAndRead 会调整您传递的字节、因为它是通过引用的。 对于多个电路板、您应该再次调整字节或复制一个预定义的字节。

    我还假设该特定板可能存在问题、可能是固件。 此主题的原始问题已解决:)  

    再次感谢、

    Dave