1

My project requires to use FTDI d2xx chip to communicate between GUI application and PMBus connected board. I would like to use Python language instead of C++ like in D2XX_Programmer's Guide.

I have found a library named ftd2xx.

But I cannot find any examples online how to use this library. How do I use FT_Write and FT_Read to send a receive commands? Does anyone has some knowledge or experience using this library or is there any similar to this I could use? Any help will be much appreciated. Thanks

nela
  • 61
  • 1
  • 11

2 Answers2

2

Under the assumption that this question is still valid - Here an example how to use the I2C mode. One has to provide/place the correct dll/so in the same folder as the script. For unix systems one has to unload the standard driver. For details see e.g. here unable to open a connection with a FTD 232 device .

class I2C:
    START_BIT           = 0x01
    STOP_BIT            = 0x02
    BREAK_ON_NACK       = 0x04
    NACK_LAST_BYTE      = 0x08
    FAST_TRANSFER_BYTES = 0x10
    FAST_TRANSFER_BITS  = 0x20
    FAST_TRANSFER       = 0x30
    NO_ADDRESS          = 0x40

    class InitError(Exception):
        pass

    class I2CChannelConfig(ctypes.Structure):
        _fields_ = [("ClockRate",   ctypes.c_int),
                    ("LatencyTimer",ctypes.c_ubyte),
                    ("Options",     ctypes.c_uint32)]
        
    def __init__(self, I2C_chn_no, clk=400000):
        self.libMPSSE = None
        try:            self.libMPSSE = ctypes.cdll.LoadLibrary("libMPSSE64.dll")
        except OSError: pass
        try:            self.libMPSSE = ctypes.cdll.LoadLibrary("libMPSSE32.dll")
        except OSError: pass
        try:            self.libMPSSE = ctypes.cdll.LoadLibrary("./libMPSSE.so")
        except OSError: pass

        if self.libMPSSE is None: raise I2C.InitError("no MPSSE lib found")

        chn_count           = ctypes.c_uint32()
        chn_conf            = I2C.I2CChannelConfig(clk,1,0)
        self.handle         = ctypes.c_void_p()

        ret = self.libMPSSE.I2C_GetNumChannels(ctypes.byref(chn_count))
        module_logger.debug("I2C_GetNumChannels status: %d number of channels: %d"%(ret,chn_count.value))
        if ret: raise I2C.InitError("I2C_GetNumChannels failed with errorcode %d"%ret)

        ret = self.libMPSSE.I2C_OpenChannel(I2C_chn_no, ctypes.byref(self.handle))
        module_logger.debug("I2C_OpenChannel status: %d handle: %s"%(ret, self.handle))
        if ret: raise I2C.InitError("I2C_OpenChannel failed with errorcode %d"%ret)

        ret = self.libMPSSE.I2C_InitChannel(self.handle,ctypes.byref(chn_conf))
        module_logger.debug("I2C_InitChannel status: %d"%ret)
        if ret: raise I2C.InitError("I2C_InitChannel failed with errorcode %d"%ret)

    def close(self):
        if self.libMPSSE:
            ret = self.libMPSSE.I2C_CloseChannel(self.handle)
            module_logger.debug("I2C_CloseChannel status: %d"%ret)
            del self.libMPSSE
            self.libMPSSE = None

    def __del__(self):
        self.close()
        
    def send(self, I2C_addr, raw):
        sent = ctypes.c_int32()
        buf  = ctypes.create_string_buffer(raw,len(raw))

        module_logger.debug("sending via I2C msg len: %d raw:\n%s" % (len(raw), raw))

        ret = self.libMPSSE.I2C_DeviceWrite(self.handle, I2C_addr, len(raw), buf, ctypes.byref(sent), I2C.START_BIT|I2C.STOP_BIT)#|I2C_TRANSFER_OPTION.FAST_TRANSFER_BYTES ignores the ACK
        module_logger.debug("I2C_DeviceWrite status: %d transfered: %d of %d"%(ret,sent.value,len(raw)))

        if ret or sent.value != len(raw):
            module_logger.warning("sending via I2C failed with ret code %d. Sent %d byte of %d." % (ret, sent.value, len(raw)))
            return False

        return True
Christian B.
  • 816
  • 6
  • 11
  • Thank you for your answer. I am also trying to use libMPSSE.dll, and I wrote a similar wrapper like your example. It is likely that I have a problem with the I2C_DISABLE_3PHASE_CLOCKING bit. When initializing the Option field with 1 (I2C_DISABLE_3PHASE_CLOCKING ) in an I2CChannelConfig structure, the I2C clock has the correct frequency, but data is not valid on both clock edges. The problem begins when I am initializing the Option field with 0 ( 3-phase-clocking enabled ). – JD. Nov 06 '20 at 14:20
  • (2) The frequency of the I2C clock is different than declared earlier (always higher), and glitches occur. Data is not valid on both clock edges also. I copied Your example, and it behaved the same as my code. - chn_conf = I2C.I2CChannelConfig(clk,1,0) - chn_conf = I2C.I2CChannelConfig(clk,1,1) Do You have any idea what could be the reason, maybe the wrong internal clock? – JD. Nov 06 '20 at 14:21
  • 1
    TBH I never check that. However, I just looked into the FTDI documents and noticed the following line:Version 1.2Corrected command used to enable 3-phase-clocking on page 8. Correct command is 0x8C instead of 0x8D. 2020-05-26 - source: https://www.ftdichip.com/Support/Documents/AppNotes/AN_113_FTDI_Hi_Speed_USB_To_I2C_Example.pdf . Have to check that the implications are. – Christian B. Nov 06 '20 at 16:52
  • 1
    Okay, I checked the ftdi_i2c.c from https://www.ftdichip.com/Support/SoftwareExamples/MPSSE/libMPSSE_Source.zip . It looks like that MPSSE_CMD_ENABLE_3PHASE_CLOCKING = 0x8C is correctly passed to the MPSSE engine while in the disabled scenario nothing is written to it (i.e. no 0x8D). Sooo maybe this is the reason why it gets messed up. You could try to recompile MPSSE_i2c with the proper command added to the MPSSE engine write. Another option would be to skip MPSSE_i2c completely and reimplement it in python directly. – Christian B. Nov 07 '20 at 10:38
0

One possibility is that you can use the more actively maintained library pylibftdi. See https://bitbucket.org/codedstructure/pylibftdi

Another possibility is that there may be existing questions on Stackoverflow which address your question. See Using FTDI D2XX drivers with Python from Raspberry Pi on raspbian soft-float and related questions.

Community
  • 1
  • 1
wwl
  • 2,025
  • 2
  • 30
  • 51
  • Thank you for your answer. I checked pylibftdi earlier but on his website he says it does not support d2xx driver which I am using in my project. And I saw that question on stack overflow but I does not answer my question how to actually use the library. I am really new into this so I am looking for some sample code how to write and read commands using this library. – nela Nov 05 '16 at 14:19