目录
MSB/BIT/BYTES/CLK EDGE等设置命令如下表
DUT
175块钱在淘宝上买的FT4232H Mini Module
硬件连接
选择USB自供电模式,无需外部电源
驱动
经多台电脑验证,win10系统可以自动识别出FT4232H,自动安装驱动,无需手动安装。
调试程序
python库ftd2xx v1.1.2安装导入
import ftd2xx as ftd
import sys, time
import ftd2xx as ftd
class FT4232SPI():
def __init__(self, index):
self.d = ftd.open(index) # 0(BDBUS)/1(CDBUS)/2(DDBUS)/3(ADBUS)
def ftd_info(self):
# print(ftd.getDeviceInfoDetail())
# print("listDevices:", ftd.listDevices())
# print("d:", self.d)
print("getDeviceInfo:", self.d.getDeviceInfo()) #Get device information for an open device.
# print("getDeviceInfoList:", self.d.getDeviceInfoList()) #'FTD2XX' object has no attribute 'getDeviceInfoList'
print("getComPortNumber:", self.d.getComPortNumber()) #Retrieves the COM port associated with a device.
print("getBitMode:", self.d.getBitMode()) #Gets the instantaneous value of the data bus.
print("getStatus:", self.d.getStatus()) #Gets the device status including number of characters in the receive queue, number of characters in the
#transmit queue, and the current event status.
# print("getLatencyTimer:", self.d.getLatencyTimer()) #Get the current value of the latency timer.
# print("getDriverVersion:", self.d.getDriverVersion()) #This function returns the D2XX driver version number.
# print("GetLibraryVersion:", self.d.GetLibraryVersion()) #'FTD2XX' object has no attribute 'GetLibraryVersion'
# print("getLibraryVersion:", ftd.getLibraryVersion())
# print("getEventStatus:", self.d.getEventStatus())
# print("getModemStatus:", self.d.getModemStatus()) #Gets the modem status and line status from the device.
print("getQueueStatus:",self.d.getQueueStatus()) #Gets the number of bytes in the receive queue.
def ftd_spi_init(self):
self.d.resetDevice() # Reset USB device
self.d.setUSBParameters(65535, 65535) # Set USB request transfer sizes to 64K
self.d.setChars(False, 0, False, 0) # Disable event and error characters
self.d.setTimeouts(5000, 5000) # Sets the read and write timeouts in milliseconds
self.d.setLatencyTimer(1) # Set the latency timer to 1mS (default is 16mS)
self.d.setFlowControl(0x0100, 0, 0)
self.d.setBitMode(0x0, 0x00) # Reset controller
self.d.setBitMode(0x0, 0x02) # Enable MPSSE mode
def ftd_spi_clkcfg(self, spiClkMHz):
sentbuffer = (0x8a, 0x97, 0x8d) # 0x8a:Disables the clk divide by 5 to allow for a 60MHz master clock.
self.d.write(bytes(sentbuffer))
div = int((60 / (spiClkMHz * 2)) - 1) # Set SPI clock
sentbuffer = (0x86, div % 256, div // 256) # 0x86:Command to set clock divisor;div%256:L of clock divisor;div//256:H of colck divisor
self.d.write(bytes(sentbuffer))
def ftd_spi_w(self, chipID, spiEnbNum, addrHex, valueHex):
'''
spiEnbNum = 3/4/5/6/7使能DBUS3/4/5/6/7,spi_enb低电平有效
'''
opc_spi_w = 0x10
if chipID == 'xxx':
addrWH = 0x7f & addrHex >> 8 # write:最高位是'0'
addrWL = 0xff & addrHex
sentbuffer = (0x80, 0xff ^ 0x01 << spiEnbNum, 0xfb, opc_spi_w, 0x02, 0x00, addrWH, addrWL, valueHex, 0x80, 0xff, 0xfb)
self.d.write(bytes(sentbuffer))
def ftd_spi_r(self, chipID, spiEnbNum, addrHex):
'''
spiEnbNum = 3/4/5/6/7使能DBUS3/4/5/6/7,spi_enb低电平有效
'''
opc_spi_w = 0x10
opc_spi_r = 0x20
if chipID == 'xxx':
addrRH = 0x80 | addrHex >> 8 # read:最高位是'1'
addrRL = 0xff & addrHex
sentbuffer = (0x80, 0xff ^ 0x01 << spiEnbNum, 0xfb, opc_spi_w, 0x01, 0x00, addrRH, addrRL, opc_spi_r, 0x00, 0x00, 0x80, 0xff, 0xfb)
self.d.write(bytes(sentbuffer))
print(self.d.getQueueStatus())
buffRead = self.d.read(7, True)
return buffRead
def ftd_bitbang_init(self, mask, mode):
'''
mask:
This sets up which bits are inputs and outputs. A bit value of
0 sets the corresponding pin to an input, a bit value of 1 sets the corresponding pin to an output.
In the case of CBUS Bit Bang, the upper nibble of this value controls which pins are inputs and outputs,
while the lower nibble controls which of the outputs are high and low.
mode = 0x1:Asynchronous Bit Bang
mode = 0x4:Synchronous Bit Bang
'''
self.d.setBitMode(mask, mode)
def ftd_bitbang_c_a(self, onNum):
'''
Asynchronous Bit-Bang mode is the same as BM-style Bit-Bang mode. On any channel configured in
asynchronous bit-bang mode, data written to the device in the normal manner will be self-clocked onto the
parallel I/O data pins (those which have been configured as outputs). Each I/O pin can be independently
set as an input or an output. The rate that the data is clocked out at is controlled by the baud rate generator.
For the data to change there has to be new data written, and the baud rate clock has to tick. If no new
data is written to the channel, the pins will hold the last value written.
'''
pass
def ftd_bitbang_c_s(self, onoffNums):
'''
The synchronous Bit-Bang mode will only update the output parallel I/O port pins whenever data is sent
from the USB interface to the parallel interface. When this is done, data is read from the USB Rx FIFO
buffer and written out on the pins. Data can only be received from the parallel pins (to the USB Tx FIFO
interface) when the parallel interface has been written to.
With Synchronous Bit-Bang mode, data will only be sent out by the FT4232H if there is space in the
FT4232H USB TXFIFO for data to be read from the parallel interface pins. This Synchronous Bit-Bang mode
will read the data bus parallel I/O pins first, before it transmits data from the USB RxFIFO. It is therefore 1
byte behind the output, and so to read the inputs for the byte that you have just sent, another byte must
be sent.
'''
pass
def ftd_close(self):
self.d.close()
def ftd_spi_test(self):
self.ftd_spi_init()
self.ftd_spi_clkcfg(1) #SPICLK = 1MHz
'''
The MPSSE can be placed in loop-back mode for diagnostic purposes.
In addition to data being transmitted out of the DO pin, it is also connected internally to the DI pin.
#0x84:This will connect the TDI / DO output to the TDO / DI input for loopback testing.
#0x85:This will disconnect the TDI output from the TDO input for loopback testing
'''
self.d.write('\x84') #仅能回读到写入的命令字,无法实现3线SPI功能
# data = 0xab # Synchronize the MPSSE by sending a bogus opcode (0xAB)
# print(d.read(1, True)) #The MPSSE will respond with "Bad Command" (0xFA) followed by the bogus opcode itself
'''
// Set initial states of the MPSSE interface
// - low byte, both pin directions and output values
// Pin name Signal Direction Config Initial State Config
// ADBUS0 TCK/SK output 1 high 1
// ADBUS1 TDI/DO output 1 low 0
// ADBUS2 TDO/DI input 0 0
// ADBUS3 TMS/CS output 1 high 1
// ADBUS4 GPIOL0 output 1 low 0
// ADBUS5 GPIOL1 output 1 low 0
// ADBUS6 GPIOL2 output 1 high 1
// ADBUS7 GPIOL3 output 1 high 1
# data = (0x80, 0x01, 0xfb) #0x80:Set Data Bits Low Bytes(ADBUS 7-0);0x00:Value;0xfb:Direction TCK/SK, TDI/D0, TMS/CS output, TDO/DI and GPIOL0 -> GPIOL3 input
# d.write(bytes(data))
'''
'''
《AN108》
3.3.1 Clock Data Bytes Out on +ve clock edge MSB first (no read)
Use if CLK starts at '1'
0x10,
LengthL,
LengthH,
Byte1
..
Byte65536 (max)
This will clock out bytes on TDI/DO from 1 to 65536 depending on the Length bytes. A length of 0x0000
will do 1 byte and a length of 0xffff will do 65536 bytes. The data is sent MSB first. Bit 7 of the first byte
is placed on TDI/D0 then the CLK pin is clocked. The data will change to the next bit on the rising edge of
the CLK pin. No data is clocked into the device on TDO/DI.
'''
chipID = 'xxx'
addr = 0x1c4
value = 0xad
EnbNum = 3
self.ftd_spi_w(chipID, EnbNum, addr, value)
print(self.ftd_spi_r(chipID, EnbNum, addr))
DACONFF_xxx = 0x00
addrlist = [0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5]
for addr in addrlist:
self.ftd_spi_w(chipID, EnbNum, addr, DACONFF_xxx)
# self.ftd_info()
self.ftd_close()
def ftd_spi_enb_test(self):
self.ftd_spi_init()
self.ftd_spi_clkcfg(1) #SPICLK = 1MHz
chipID = 'xxx'
EnbNum = 7
addr = 0x1c4
value = 0xad
self.ftd_spi_w(chipID, EnbNum, addr, value)
self.ftd_close()
def ftd_bitbang_test(self):
self.ftd_bitbang_init(0xff, 0x1)
self.d.write(bytes(0x01))
self.ftd_close()
if __name__ == '__main__':
adbus = FT4232SPI(3) # 0(BDBUS)/1(CDBUS)/2(DDBUS)/3(ADBUS)
adbus.ftd_info()
adbus.ftd_spi_test()
#
# bdbus = FT4232SPI(0) # 0(BDBUS)/1(CDBUS)/2(DDBUS)/3(ADBUS)
# bdbus.ftd_info()
# # bdbus.ftd_spi_enb_test()
#
# cdbus = FT4232SPI(1) # 0(BDBUS)/1(CDBUS)/2(DDBUS)/3(ADBUS)
# cdbus.ftd_info()
# # cdbus.ftd_bitbang_test()
#
# ddbus = FT4232SPI(2) # 0(BDBUS)/1(CDBUS)/2(DDBUS)/3(ADBUS)
# ddbus.ftd_info()
需要特别注意的是:
- self.d = ftd.open(index) # 0(bdbus)/1(cdbus)/2(ddbus)/3(adbus),adbus对应的index不是“0”,而是“3”,所以,最好通过下面一组指令确认各个dbus对应的index
d1 = ftd.open(0)
print("getDeviceInfo:", d1.getDeviceInfo())
d2 = ftd.open(1)
print("getDeviceInfo:", d2.getDeviceInfo())
d3 = ftd.open(0)
print("getDeviceInfo:", d3.getDeviceInfo())
d4 = ftd.open(1)
print("getDeviceInfo:", d4.getDeviceInfo())
- 单byte指令发送必须用如下形式——
self.d.write('\x84')
- 多byte组合指令发送形式如下——
sentbuffer = (0x80, 0xff, 0xfb)
self.d.write(bytes(sentbuffer))
调试结果
MSB/BIT/BYTES/CLK EDGE等设置命令如下表
详见《Command Processor for MPSSE and MCU Host Bus Emulation Modes》