diff --git a/ft4222/clibft4222.pxd b/ft4222/clibft4222.pxd index 4c2979c..239f279 100644 --- a/ft4222/clibft4222.pxd +++ b/ft4222/clibft4222.pxd @@ -152,7 +152,7 @@ cdef extern from "libft4222.h": FT4222_STATUS FT4222_GetMaxTransferSize(FT_HANDLE ftHandle, uint16* pMaxSize) FT4222_STATUS FT4222_SetEventNotification(FT_HANDLE ftHandle, DWORD mask, PVOID param) FT4222_STATUS FT4222_GetVersion(FT_HANDLE ftHandle, FT4222_Version* pVersion) - # FT4222 I2C Functions + # FT4222 I2C Master Functions FT4222_STATUS FT4222_I2CMaster_Read(FT_HANDLE ftHandle, uint16 deviceAddress, uint8* buffer, uint16 bufferSize, uint16* sizeTransferred) FT4222_STATUS FT4222_I2CMaster_Write(FT_HANDLE ftHandle, uint16 deviceAddress, uint8* buffer, uint16 bufferSize, uint16* sizeTransferred) FT4222_STATUS FT4222_I2CMaster_Init(FT_HANDLE ftHandle, uint32 kbps) @@ -160,6 +160,16 @@ cdef extern from "libft4222.h": FT4222_STATUS FT4222_I2CMaster_WriteEx(FT_HANDLE ftHandle, uint16 deviceAddress, uint8 flag, uint8* buffer, uint16 bufferSize, uint16* sizeTransferred) FT4222_STATUS FT4222_I2CMaster_Reset(FT_HANDLE ftHandle) FT4222_STATUS FT4222_I2CMaster_GetStatus(FT_HANDLE ftHandle, uint8 *controllerStatus) + # FT4222 I2C Slave Functions + FT4222_STATUS FT4222_I2CSlave_Init(FT_HANDLE ftHandle); + FT4222_STATUS FT4222_I2CSlave_Reset(FT_HANDLE ftHandle); + FT4222_STATUS FT4222_I2CSlave_GetAddress(FT_HANDLE ftHandle, uint8*addr); + FT4222_STATUS FT4222_I2CSlave_SetAddress(FT_HANDLE ftHandle, uint8 addr); + FT4222_STATUS FT4222_I2CSlave_GetRxStatus(FT_HANDLE ftHandle, uint16*pRxSize); + FT4222_STATUS FT4222_I2CSlave_Read(FT_HANDLE ftHandle, uint8*buffer, uint16 bufferSize, uint16*sizeTransferred); + FT4222_STATUS FT4222_I2CSlave_Write(FT_HANDLE ftHandle, uint8*buffer, uint16 bufferSize, uint16*sizeTransferred); + FT4222_STATUS FT4222_I2CSlave_SetClockStretch(FT_HANDLE ftHandle, BOOL enable); + FT4222_STATUS FT4222_I2CSlave_SetRespWord(FT_HANDLE ftHandle, uint8 responseWord); # FT4222 GPIO Functions FT4222_STATUS FT4222_GPIO_Init(FT_HANDLE ftHandle, GPIO_Dir gpioDir[4]) FT4222_STATUS FT4222_GPIO_Read(FT_HANDLE ftHandle, GPIO_Port portNum, BOOL* value) @@ -184,4 +194,3 @@ cdef extern from "libft4222.h": FT4222_STATUS FT4222_SPISlave_GetRxStatus(FT_HANDLE ftHandle, uint16* pRxSize); FT4222_STATUS FT4222_SPISlave_Read(FT_HANDLE ftHandle, uint8* buffer, uint16 bufferSize, uint16* sizeOfRead); FT4222_STATUS FT4222_SPISlave_Write(FT_HANDLE ftHandle, uint8* buffer, uint16 bufferSize, uint16* sizeTransferred); - FT4222_STATUS FT4222_SPISlave_RxQuickResponse(FT_HANDLE ftHandle, BOOL enable); diff --git a/ft4222/ft4222.pyx b/ft4222/ft4222.pyx index fc14dff..2cc614b 100644 --- a/ft4222/ft4222.pyx +++ b/ft4222/ft4222.pyx @@ -181,6 +181,12 @@ cdef class FT4222: FT4222_UnInitialize(self._handle) FT_Close(self._handle) + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + def close(self): """Closes the device.""" status = FT4222_UnInitialize(self._handle) @@ -608,6 +614,149 @@ cdef class FT4222: return ControllerStatus(cs) raise FT4222DeviceError, status + def i2cSlave_Init(self): + """Initialize the FT4222H as an I2C slave. + + Raises: + FT4222DeviceError: on error + + """ + status = FT4222_I2CSlave_Init(self._handle) + if status != FT4222_OK: + raise FT4222DeviceError, status + + def i2cSlave_Reset(self): + """Reset i2c slave + + Raises: + FT4222DeviceError: on error + + """ + status = FT4222_I2CSlave_Reset(self._handle) + if status != FT4222_OK: + raise FT4222DeviceError, status + + def i2cSlave_GetAddress(self): + """Get address of slave device + + Returns: + int: address of slave device + + Raises: + FT4222DeviceError: on error + + """ + cdef uint8 addr + status = FT4222_I2CSlave_GetAddress(self._handle, &addr) + if status == FT4222_OK: + return addr + raise FT4222DeviceError, status + + def i2cSlave_SetAddress(self, addr): + """Set address of slave device + + Args: + addr(int): address of slave device + + Raises: + FT4222DeviceError: on error + + """ + status = FT4222_I2CSlave_SetAddress(self._handle, addr) + if status != FT4222_OK: + raise FT4222DeviceError, status + + def i2cSlave_GetRxStatus(self): + """Get rx byte count of slave device + + Returns: + int: rx byte count of slave device + + Raises: + FT4222DeviceError: on error + + """ + cdef uint16 rxSize + status = FT4222_I2CSlave_GetRxStatus(self._handle, &rxSize) + if status == FT4222_OK: + return rxSize + raise FT4222DeviceError, status + + def i2cSlave_Read(self, bytesToRead): + """Read bytes from master device + + Args: + bytesToRead (int): Number of bytes to read from master + + Returns: + bytes: Bytes read from master + + Raises: + FT4222DeviceError: on error + + """ + cdef: + array[uint8] buf = array('B', []) + uint16 bytesRead + resize(buf, bytesToRead) + status = FT4222_I2CSlave_Read(self._handle, buf.data.as_uchars, bytesToRead, &bytesRead) + resize(buf, bytesRead) + if status == FT4222_OK: + return bytes(buf) + raise FT4222DeviceError, status + + def i2cSlave_Write(self, data): + """write data to master + + Args: + data (int, bytes, bytearray): Data to write to master + + Returns: + int: Bytes sent to master + + Raises: + FT4222DeviceError: on error + + """ + if isinstance(data, int): + data = bytes([data]) + elif not isinstance(data, (bytes, bytearray)): + raise TypeError("the data argument must be of type 'int', 'bytes' or 'bytearray'") + cdef: + uint16 bytesSent + uint8* cdata = data + status = FT4222_I2CSlave_Write(self._handle, cdata, len(data), &bytesSent) + if status == FT4222_OK: + return bytesSent + raise FT4222DeviceError, status + + def i2cSlave_SetClockStretch(self, enable): + """Set clock stretch + + Args: + enable (bool): True for enable, False for disable + + Raises: + FT4222DeviceError: on error + + """ + status = FT4222_I2CSlave_SetClockStretch(self._handle, enable) + if status != FT4222_OK: + raise FT4222DeviceError, status + + def i2cSlave_SetRespWord(self, responseWord): + """Set response word + + Args: + enable (bool): True for enable, False for disable + + Raises: + FT4222DeviceError: on error + + """ + status = FT4222_I2CSlave_SetRespWord(self._handle, responseWord) + if status != FT4222_OK: + raise FT4222DeviceError, status def spi_Reset(self): """Reset the SPI master or slave device diff --git a/linux/ReadMe.txt b/linux/ReadMe.txt new file mode 100755 index 0000000..6225d39 --- /dev/null +++ b/linux/ReadMe.txt @@ -0,0 +1,107 @@ + + + +libft4222 for Linux +------------------- + +FTDI's libft4222 allows access to, and control of, the FT4222H. +Depending on configuration, the FT4222H presents 1, 2 or 4 interfaces +for I2C, SPI and GPIO functions. Please search ftdichip.com for the +FT4222H data sheet, and Application Note AN_329 which describes the +libft4222 API. + +The Linux version of libft4222 includes (statically links to) FTDI's +libftd2xx which itself includes an unmodified version of libusb +(http://libusb.info) which is distributed under the terms of the GNU +Lesser General Public License (see http://www.gnu.org/licenses). Sources +for libusb, plus re-linkable object files are included in the libftd2xx +distribution, available from ftdichip.com. + + +Installing +---------- + +1. tar xfvz libft4222-1.4.4.44.tgz + +This unpacks the archive, creating the following directory structure: + + build-arm-v6 + build-i386 + build-x86_64 + examples + libft4222.h + ftd2xx.h + WinTypes.h + install4222.sh + +2. sudo ./install4222.sh + +This copies the library (libft4222.so.1.4.4.44) and headers to +/usr/local/lib and /usr/local/include respectively. Also it creates a +version-independent symbolic link, libft4222.so. + +Alternatively, you may manually copy the library and headers to a +custom location. + + +Building +-------- + +1. cd examples + +2. cc get-version.c -lft4222 -Wl,-rpath,/usr/local/lib + +With an FT4222H device connected to a USB port, try: + +3. sudo ./a.out + +You should see a message similar to this: + + Chip version: 42220100, LibFT4222 version: 010200E5 + +If you see a message such as "No devices connected" or "No FT4222H detected", +this may indicate that: + + a. There is no FT4222H connected. Check by running 'lsusb', which + should output something similar to: + + Bus 001 Device 005: ID 0403:601c Future Technology Devices International, Ltd + + b. Your program did not run with sufficient privileges to access USB. + Use 'sudo', or 'su', or run as root. + +If you see an error message about libft4222.so having an invalid ABI, please +try to upgrade glibc to version 2.10 or above. + +Release Notes +------------- + +1.4.4.44 + Fix issue. Frequency 100K~400K in I2C Master is not accurate. + Add Feature. Add API FT4222_I2CMaster_ResetBus. This function can reset i2c bus when it is abnormal. + Add Feature. Add API FT4222_SPIMaster_SetCS. It can determine the CS is high or low when SPI bus is active. The default value is active-low. + Remove Feature. Remove API FT4222_SPISlave_RxQuickResponse. It may cause data lost sometimes. + Add Feature. Add license announce in libft4222.h + +1.4.4.9 + Add i486 and Arm-V7-A83T support. + Fix potential FT4222_I2CMaster_Read and FT4222_I2CMaster_ReadEx data lost. + Fix issue. FT4222_I2CMaster_WriteEx does not return correct sizeTransferred. + Fix issue. FT4222_SPIMaster_MultiReadWrite does not return correct sizeOfRead when multiReadBytes equal to zero + +1.4.2.184 + New API gives SPI Slave protocol options. + Fixed potential SPI Slave data loss. + Fixed potential GPIO read error. + Fixed potential SPISlave_GetMaxTransferSize error. + Fixed potential inability for GPIO_Read to get interrupt status. + +1.2.1.4 + Added Linux support, extended I2C Master API. + Added portable C examples. + +1.1.0.0 + Added 64-bit Windows support. + +1.0.0.0 + Initial version. Windows only. diff --git a/linux/build-arm-hisiv300/libft4222.so.1.4.4.44 b/linux/build-arm-hisiv300/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..9d9dc16 Binary files /dev/null and b/linux/build-arm-hisiv300/libft4222.so.1.4.4.44 differ diff --git a/linux/build-arm-v5-sf/libft4222.so.1.4.4.44 b/linux/build-arm-v5-sf/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..477861c Binary files /dev/null and b/linux/build-arm-v5-sf/libft4222.so.1.4.4.44 differ diff --git a/linux/build-arm-v7-hf/libft4222.so b/linux/build-arm-v7-hf/libft4222.so new file mode 100755 index 0000000..e2cfb29 Binary files /dev/null and b/linux/build-arm-v7-hf/libft4222.so differ diff --git a/linux/build-arm-v7-hf/libft4222.so.1.4.4.44 b/linux/build-arm-v7-hf/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..e2cfb29 Binary files /dev/null and b/linux/build-arm-v7-hf/libft4222.so.1.4.4.44 differ diff --git a/linux/build-i486/libft4222.so.1.4.4.44 b/linux/build-i486/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..08f5136 Binary files /dev/null and b/linux/build-i486/libft4222.so.1.4.4.44 differ diff --git a/linux/build-mips-eglibc-hf/libft4222.so.1.4.4.44 b/linux/build-mips-eglibc-hf/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..fcf898c Binary files /dev/null and b/linux/build-mips-eglibc-hf/libft4222.so.1.4.4.44 differ diff --git a/linux/build-pentium/libft4222.so.1.4.4.44 b/linux/build-pentium/libft4222.so.1.4.4.44 new file mode 100755 index 0000000..ee5fda9 Binary files /dev/null and b/linux/build-pentium/libft4222.so.1.4.4.44 differ diff --git a/linux/examples/get-version.c b/linux/examples/get-version.c new file mode 100755 index 0000000..182d00b --- /dev/null +++ b/linux/examples/get-version.c @@ -0,0 +1,160 @@ +/* Minimal program to link to LibFT4222. + * Displays library and chip version numbers. + * + * Windows instructions: + * 1. Copy ftd2xx.h and ftd2xx.lib from driver package to current directory. + * 2. Build with MSVC: cl i2cm.c LibFT4222.lib ftd2xx.lib + * or + * Build with MinGW: gcc i2cm.c LibFT4222.lib ftd2xx.lib + * 3. get-version.exe + * + * Linux instructions: + * 1. Ensure libft4222.so is in the library search path (e.g. /usr/local/lib) + * 2. Ensure libft4222.h, ftd2xx.h and WinTypes.h are in the Include search + * path (e.g. /usr/local/include). + * 3. cc get-version.c -lft4222 -Wl,-rpath,/usr/local/lib + * 4. sudo ./a.out + * + * Mac instructions: + * 1. Ensure libft4222.dylib is in the library search path (e.g. /usr/local/lib) + * 2. Ensure libft4222.h, ftd2xx.h and WinTypes.h are in the Include search + * path (e.g. /usr/local/include). + * 3. cc get-version.c -lft4222 -Wl,-L/usr/local/lib + * 4. ./a.out + */ +#include +#include +#include +#include "ftd2xx.h" +#include "libft4222.h" + + + +static void showVersion(DWORD locationId) +{ + FT_STATUS ftStatus; + FT_HANDLE ftHandle = (FT_HANDLE)NULL; + FT4222_STATUS ft4222Status; + FT4222_Version ft4222Version; + + ftStatus = FT_OpenEx((PVOID)(uintptr_t)locationId, + FT_OPEN_BY_LOCATION, + &ftHandle); + if (ftStatus != FT_OK) + { + printf("FT_OpenEx failed (error %d)\n", + (int)ftStatus); + return; + } + + // Get version of library and chip. + ft4222Status = FT4222_GetVersion(ftHandle, + &ft4222Version); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_GetVersion failed (error %d)\n", + (int)ft4222Status); + } + else + { + printf(" Chip version: %08X, LibFT4222 version: %08X\n", + (unsigned int)ft4222Version.chipVersion, + (unsigned int)ft4222Version.dllVersion); + } + + (void)FT_Close(ftHandle); +} + + + +int main (void) +{ + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo = NULL; + DWORD numDevs = 0; + int i; + int retCode = 0; + int found4222 = 0; + + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) + { + printf("FT_CreateDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -10; + goto exit; + } + + if (numDevs == 0) + { + printf("No devices connected.\n"); + retCode = -20; + goto exit; + } + + /* Allocate storage */ + devInfo = calloc((size_t)numDevs, + sizeof(FT_DEVICE_LIST_INFO_NODE)); + if (devInfo == NULL) + { + printf("Allocation failure.\n"); + retCode = -30; + goto exit; + } + + /* Populate the list of info nodes */ + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus != FT_OK) + { + printf("FT_GetDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -40; + goto exit; + } + + for (i = 0; i < (int)numDevs; i++) + { + if (devInfo[i].Type == FT_DEVICE_4222H_0 || + devInfo[i].Type == FT_DEVICE_4222H_1_2) + { + // In mode 0, the FT4222H presents two interfaces: A and B. + // In modes 1 and 2, it presents four interfaces: A, B, C and D. + + size_t descLen = strlen(devInfo[i].Description); + + if ('A' == devInfo[i].Description[descLen - 1]) + { + // Interface A may be configured as an I2C master. + printf("\nDevice %d: '%s'\n", + i, + devInfo[i].Description); + showVersion(devInfo[i].LocId); + } + else + { + // Interface B, C or D. + // No need to repeat version info of same chip. + } + + found4222++; + } + + if (devInfo[i].Type == FT_DEVICE_4222H_3) + { + // In mode 3, the FT4222H presents a single interface. + printf("\nDevice %d: '%s'\n", + i, + devInfo[i].Description); + showVersion(devInfo[i].LocId); + + found4222++; + } + } + + if (found4222 == 0) + printf("No FT4222H detected.\n"); + +exit: + free(devInfo); + return retCode; +} diff --git a/linux/examples/i2cm.c b/linux/examples/i2cm.c new file mode 100755 index 0000000..c407cec --- /dev/null +++ b/linux/examples/i2cm.c @@ -0,0 +1,488 @@ +/* Read and write I2C Slave EEPROM. + * Tested with 24LC01B (128 x 8-bits). + * + * Windows build instructions: + * 1. Copy ftd2xx.h and 32-bit ftd2xx.lib from driver package. + * 2. Build. + * MSVC: cl i2cm.c LibFT4222.lib ftd2xx.lib + * MinGW: gcc i2cm.c LibFT4222.lib ftd2xx.lib + * + * Linux instructions: + * 1. Ensure libft4222.so is in the library search path (e.g. /usr/local/lib) + * 2. gcc i2cm.c -lft4222 -Wl,-rpath,/usr/local/lib + * 3. sudo ./a.out + * + * Mac instructions: + * 1. Ensure libft4222.dylib is in the library search path (e.g. /usr/local/lib) + * 2. gcc i2cm.c -lft4222 -Wl,-L/usr/local/lib + * 3. ./a.out + */ +#include +#include +#include +#include +#include +#include "ftd2xx.h" +#include "libft4222.h" + +#ifndef _countof + #define _countof(a) (sizeof((a))/sizeof(*(a))) +#endif + +#define EEPROM_BYTES 128 // 24LC01B has 128 x 8 bits of storage +#define BYTES_PER_PAGE 8 // 24LC01B can be written in 8-byte pages + + +static uint8 originalContent[EEPROM_BYTES]; +static uint8 newContent[EEPROM_BYTES]; +static char slogan1[EEPROM_BYTES + 1] = + "FTDI Chip strives to Make Design Easy with our modules, cables " + "and integrated circuits for USB connectivity and display systems."; + +static char slogan2[EEPROM_BYTES + 1] = + "FT4222H: Hi-Speed USB 2.0 QSPI/I2C device controller. QFN32, " + "1.8/2.5/3.3V IO, 128 bytes OTP. Requires 12 MHz external crystal."; + + + +static void hexdump(uint8 *address, uint16 length) +{ + char buf[3*8 + 2 + 8 + 1]; + char subString[4]; + int f; + int offsetInLine = 0; + char printable; + char unprinted = 0; + + buf[0] = '\0'; + + for (f = 0; f < length; f++) + { + offsetInLine = f % 8; + + if (offsetInLine == 0) + { + // New line. Display previous line... + printf("%s\n%p: ", buf, address + f); + unprinted = 0; + // ...and clear buffer ready for the new line. + memset(buf, (int)' ', sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + + sprintf(subString, "%02x ", (unsigned int)address[f]); + memcpy(&buf[offsetInLine * 3], subString, 3); + + if ( isprint((int)address[f]) ) + printable = (char)address[f]; + else + printable = '.'; + sprintf(subString, "%c", printable); + memcpy(&buf[3*8 + 2 + offsetInLine], subString, 1); + + unprinted++; // Remember + } + + if (unprinted) + printf("%s\n", buf); + + printf("\n"); +} + + +/* Sets given slave's current-address counter to specified value */ +static FT4222_STATUS setWordAddress(FT_HANDLE ftHandle, + const uint16 slaveAddr, + uint8 wordAddress) +{ + FT4222_STATUS ft4222Status; + uint16 bytesToWrite = 1; + uint16 bytesWritten = 0; + + ft4222Status = FT4222_I2CMaster_Write(ftHandle, + slaveAddr, + &wordAddress, + bytesToWrite, + &bytesWritten); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Write 1 failed (error %d)\n", + (int)ft4222Status); + return ft4222Status; + } + + if (bytesWritten != bytesToWrite) + { + printf("FT4222_I2CMaster_Write wrote %u of %u bytes.\n", + bytesWritten, + bytesToWrite); + } + + return ft4222Status; +} + + +/* Call this after writing to the EEPROM. + * This attempts to set the EEPROM's word address then + * checks to see if the request was NACKed (which means + * the EEPROM is still busy). + */ +static FT4222_STATUS pollAddressAck(FT_HANDLE ftHandle, + const uint16 slaveAddr) +{ + FT4222_STATUS ft4222Status = FT4222_OK; + uint8 controllerStatus = 0; + uint16 tries = 0; + + // 25 retries works for 24LC01B at 400 kHz. + for (tries = 0; tries < 25; tries++) + { + // Try to set slave EEPROM's current word address counter. + ft4222Status = setWordAddress(ftHandle, + slaveAddr, + 0); + if (FT4222_OK != ft4222Status) + { + return ft4222Status; + } + + ft4222Status = FT4222_I2CMaster_GetStatus(ftHandle, + &controllerStatus); + if (ft4222Status != FT4222_OK) + { + printf("FT4222_I2CMaster_GetStatus failed (%d).\n", + ft4222Status); + return ft4222Status; + } + +#ifdef DEBUG_I2C_STATUS + printf("%02X ", controllerStatus); +#endif // DEBUG_I2C_STATUS + + // Typically BUS_BUSY precedes ERROR state + if (I2CM_BUS_BUSY(controllerStatus)) + continue; + + // I've observed IDLE both before and after the ERROR state. + if (I2CM_IDLE(controllerStatus)) + continue; + + // Bus is not busy, and controller not idle, so check for error. + if (!I2CM_ADDRESS_NACK(controllerStatus)) + break; + } + +#ifdef DEBUG_I2C_STATUS + printf("%u tries, %02X\n", tries, controllerStatus); +#endif // DEBUG_I2C_STATUS + + return ft4222Status; +} + + +static int exercise4222(DWORD locationId) +{ + int success = 0; + FT_STATUS ftStatus; + FT_HANDLE ftHandle = (FT_HANDLE)NULL; + FT4222_STATUS ft4222Status; + FT4222_Version ft4222Version; + const uint16 slaveAddr = 0x50; + uint16 bytesToRead ; + uint16 bytesRead = 0; + uint16 bytesToWrite; + uint16 bytesWritten = 0; + char *writeBuffer; + uint8_t pageBuffer[BYTES_PER_PAGE + 1]; + int page; + + + ftStatus = FT_OpenEx((PVOID)(uintptr_t)locationId, + FT_OPEN_BY_LOCATION, + &ftHandle); + if (ftStatus != FT_OK) + { + printf("FT_OpenEx failed (error %d)\n", + (int)ftStatus); + goto exit; + } + + ft4222Status = FT4222_GetVersion(ftHandle, + &ft4222Version); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_GetVersion failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + printf("Chip version: %08X, LibFT4222 version: %08X\n", + (unsigned int)ft4222Version.chipVersion, + (unsigned int)ft4222Version.dllVersion); + + // Configure the FT4222 as an I2C Master + ft4222Status = FT4222_I2CMaster_Init(ftHandle, 400); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Init failed (error %d)!\n", + ft4222Status); + goto exit; + } + + // Reset the I2CM registers to a known state. + ft4222Status = FT4222_I2CMaster_Reset(ftHandle); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Reset failed (error %d)!\n", + ft4222Status); + goto exit; + } + + // Before reading EEPROM, set buffer to known content + memset(originalContent, '!', EEPROM_BYTES); + + // Reset slave EEPROM's current word address counter. + ft4222Status = setWordAddress(ftHandle, + slaveAddr, + 0); + if (FT4222_OK != ft4222Status) + { + goto exit; + } + + // Sequential read from slave EEPROM's current word address. + bytesToRead = _countof(originalContent); + ft4222Status = FT4222_I2CMaster_Read(ftHandle, + slaveAddr, + originalContent, + bytesToRead, + &bytesRead); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Read failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + if (bytesRead != bytesToRead) + { + printf("FT4222_I2CMaster_Read read %u of %u bytes.\n", + bytesRead, + bytesToRead); + goto exit; + } + + if (0 != memcmp(originalContent, slogan1, EEPROM_BYTES)) + writeBuffer = slogan1; + else + writeBuffer = slogan2; + + printf("Writing \"%.20s...\"\n", writeBuffer); + + for (page = 0; page < EEPROM_BYTES/BYTES_PER_PAGE; page++) + { + // First byte to write is address (in EEPROM) of first byte in page. + pageBuffer[0] = page * BYTES_PER_PAGE; + + // Copy a page's worth of data into the rest of pageBuffer. + memcpy(&pageBuffer[1], + writeBuffer + page * BYTES_PER_PAGE, + BYTES_PER_PAGE); + + bytesToWrite = BYTES_PER_PAGE + 1; + ft4222Status = FT4222_I2CMaster_Write(ftHandle, + slaveAddr, + pageBuffer, + bytesToWrite, + &bytesWritten); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Write 2 failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + if (bytesWritten != bytesToWrite) + { + printf("FT4222_I2CMaster_Write wrote %u of %u bytes.\n", + bytesWritten, + bytesToWrite); + goto exit; + } + + // Wait for EEPROM's write-cycle to complete. + ft4222Status = pollAddressAck(ftHandle, slaveAddr); + if (FT4222_OK != ft4222Status) + { + goto exit; + } + } + + memset(newContent, '!', EEPROM_BYTES); + + // Reset slave EEPROM's current word address counter. + ft4222Status = setWordAddress(ftHandle, + slaveAddr, + 0); + if (FT4222_OK != ft4222Status) + { + goto exit; + } + + // Sequential read from slave EEPROM's current word address. + bytesToRead = _countof(newContent); + ft4222Status = FT4222_I2CMaster_Read(ftHandle, + slaveAddr, + newContent, + bytesToRead, + &bytesRead); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_I2CMaster_Read failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + if (bytesRead != bytesToRead) + { + printf("FT4222_I2CMaster_Read read %u of %u bytes.\n", + bytesRead, + bytesToRead); + goto exit; + } + + printf("\nOriginal content of EEPROM:\n"); + hexdump(originalContent, EEPROM_BYTES); + + printf("\nNew content of EEPROM:\n"); + hexdump(newContent, EEPROM_BYTES); + + success = 1; + +exit: + if (ftHandle != (FT_HANDLE)NULL) + { + (void)FT4222_UnInitialize(ftHandle); + (void)FT_Close(ftHandle); + } + + return success; +} + + +static int testFT4222(void) +{ + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo = NULL; + DWORD numDevs = 0; + int i; + int retCode = 0; + int found4222 = 0; + + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) + { + printf("FT_CreateDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -10; + goto exit; + } + + if (numDevs == 0) + { + printf("No devices connected.\n"); + retCode = -20; + goto exit; + } + + /* Allocate storage */ + devInfo = calloc((size_t)numDevs, + sizeof(FT_DEVICE_LIST_INFO_NODE)); + if (devInfo == NULL) + { + printf("Allocation failure.\n"); + retCode = -30; + goto exit; + } + + /* Populate the list of info nodes */ + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus != FT_OK) + { + printf("FT_GetDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -40; + goto exit; + } + + for (i = 0; i < (int)numDevs; i++) + { + unsigned int devType = devInfo[i].Type; + size_t descLen; + + if (devType == FT_DEVICE_4222H_0) + { + // In mode 0, the FT4222H presents two interfaces: A and B. + descLen = strlen(devInfo[i].Description); + + if ('A' == devInfo[i].Description[descLen - 1]) + { + // Interface A may be configured as an I2C master. + printf("\nDevice %d is interface A of mode-0 FT4222H:\n", + i); + printf(" 0x%08x %s %s\n", + (unsigned int)devInfo[i].ID, + devInfo[i].SerialNumber, + devInfo[i].Description); + (void)exercise4222(devInfo[i].LocId); + } + else + { + // Interface B of mode 0 is reserved for GPIO. + printf("Skipping interface B of mode-0 FT4222H.\n"); + } + + found4222++; + } + + if (devType == FT_DEVICE_4222H_1_2) + { + // In modes 1 and 2, the FT4222H presents four interfaces but + // none is suitable for I2C. + descLen = strlen(devInfo[i].Description); + + printf("Skipping interface %c of mode-1/2 FT4222H.\n", + devInfo[i].Description[descLen - 1]); + + found4222++; + } + + if (devType == FT_DEVICE_4222H_3) + { + // In mode 3, the FT4222H presents a single interface. + // It may be configured as an I2C Master. + printf("\nDevice %d is mode-3 FT4222H (single Master/Slave):\n", + i); + printf(" 0x%08x %s %s\n", + (unsigned int)devInfo[i].ID, + devInfo[i].SerialNumber, + devInfo[i].Description); + (void)exercise4222(devInfo[i].LocId); + + found4222++; + } + } + + if (!found4222) + printf("No FT4222 found.\n"); + +exit: + free(devInfo); + return retCode; +} + +int main (void) +{ + return testFT4222(); +} + diff --git a/linux/examples/spim.c b/linux/examples/spim.c new file mode 100755 index 0000000..224d030 --- /dev/null +++ b/linux/examples/spim.c @@ -0,0 +1,524 @@ +/* Read and write SPI Slave EEPROM. + * Tuned for AT93C46 (128 x 8-bits). + * Windows build instructions: + * 1. Copy ftd2xx.h and 32-bit ftd2xx.lib from driver package. + * 2. Build. + * MSVC: cl spim.c LibFT4222.lib ftd2xx.lib + * MinGW: gcc spim.c LibFT4222.lib ftd2xx.lib + * Linux instructions: + * 1. Ensure libft4222.so is in the library search path (e.g. /usr/local/lib) + * 2. gcc spim.c -lft4222 -Wl,-rpath,/usr/local/lib + * 3. sudo ./a.out + * + * Mac instructions: + * 1. Ensure libft4222.dylib is in the library search path (e.g. /usr/local/lib) + * 2. cc spim.c -lft4222 -Wl,-L/usr/local/lib + * 3. ./a.out + */ +#include +#include +#include +#include +#include +#include "ftd2xx.h" +#include "libft4222.h" + +#ifndef _countof + #define _countof(a) (sizeof((a))/sizeof(*(a))) +#endif + +#define EEPROM_BYTES 128 // AT93C46 has 128 x 8 bits of storage + +// SPI Master can assert SS0O in single mode +// SS0O and SS1O in dual mode, and +// SS0O, SS1O, SS2O and SS3O in quad mode. +#define SLAVE_SELECT(x) (1 << (x)) + +static uint8 originalContent[EEPROM_BYTES]; +static uint8 newContent[EEPROM_BYTES]; +static char slogan1[EEPROM_BYTES + 1] = + "FTDI Chip strives to Make Design Easy with our modules, cables " + "and integrated circuits for USB connectivity and display systems."; +static char slogan2[EEPROM_BYTES + 1] = + "FT4222H: Hi-Speed USB 2.0 QSPI/I2C device controller. QFN32, " + "1.8/2.5/3.3V IO, 128 bytes OTP. Requires 12 MHz external crystal."; + + + +static void hexdump(uint8 *address, uint16 length) +{ + char buf[3*8 + 2 + 8 + 1]; + char subString[4]; + int f; + int offsetInLine = 0; + char printable; + char unprinted = 0; + + buf[0] = '\0'; + + for (f = 0; f < length; f++) + { + offsetInLine = f % 8; + + if (offsetInLine == 0) + { + // New line. Display previous line... + printf("%s\n%p: ", buf, address + f); + unprinted = 0; + // ...and clear buffer ready for the new line. + memset(buf, (int)' ', sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + + sprintf(subString, "%02x ", (unsigned int)address[f]); + memcpy(&buf[offsetInLine * 3], subString, 3); + + if ( isprint((int)address[f]) ) + printable = (char)address[f]; + else + printable = '.'; + sprintf(subString, "%c", printable); + memcpy(&buf[3*8 + 2 + offsetInLine], subString, 1); + + unprinted++; // Remember + } + + if (unprinted) + printf("%s\n", buf); + + printf("\n"); +} + + + +/** + * Enable write (and erase) operations. AT93C46 disables them + * at reset. + * + * @param ftHandle Handle of open FT4222. + * + * @return 1 for success; 0 for failure. + */ +static int eeprom_enable_writes(FT_HANDLE ftHandle) +{ + FT4222_STATUS ft4222Status; + int success = 1; + uint16 bytesToTransceive; + uint16 bytesTransceived; + uint8 command[2] = {0x04, 0xFF}; + uint8 response[2] = {0, 0}; + + // Start bit (1) + opcode (00) + 11xxxxxx, all padded with + // leading zeroes to make a multiple of 8 bits. + bytesToTransceive = 2; + + ft4222Status = FT4222_SPIMaster_SingleReadWrite( + ftHandle, + response, + command, + bytesToTransceive, + &bytesTransceived, + TRUE); // de-assert slave-select afterwards + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPIMaster_SingleReadWrite failed (error %d)!\n", + ft4222Status); + success = 0; + goto exit; + } + + if (bytesTransceived != bytesToTransceive) + { + printf("FT4222_SPIMaster_SingleReadWrite " + "transceived %u bytes instead of %u.\n", + bytesTransceived, + bytesToTransceive); + success = 0; + goto exit; + } + +exit: + return success; +} + + + +/** + * Write a byte to a specified EEPROM address. + * + * @param ftHandle Handle of open FT4222. + * @param address EEPROM-internal memory location (7 bits). + * @param data 8-bit data to be stored in address. + * + * @return 1 for success, 0 for failure. + */ +static int eeprom_write(FT_HANDLE ftHandle, + const uint8 address, + const uint8 data) +{ + FT4222_STATUS ft4222Status; + int success = 1; + int i; + int j; + int writeComplete; + uint16 bytesToTransceive; + uint16 bytesTransceived; + uint8 command[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8 response[10] = {42, 42, 42, 42, 42, 42, 42, 42, 42, 42}; + + // Start bit (1) + opcode (01) + 7-bit address, all padded with + // leading zeroes to make a multiple of 8 bits. + command[0] = 0x02; + command[1] = 0x80 | address; + command[2] = data; + + bytesToTransceive = 3; + + ft4222Status = FT4222_SPIMaster_SingleReadWrite( + ftHandle, + response, + command, + bytesToTransceive, + &bytesTransceived, + TRUE); // de-assert slave-select afterwards + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPIMaster_SingleReadWrite failed (error %d)!\n", + ft4222Status); + success = 0; + goto exit; + } + + if (bytesTransceived != bytesToTransceive) + { + printf("FT4222_SPIMaster_SingleReadWrite " + "transceived %u bytes instead of %u.\n", + bytesTransceived, + bytesToTransceive); + success = 0; + goto exit; + } + + // Previous transceive de-asserted slave-select; the following transceive + // asserts it and keeps it asserted. Together this creates a short pulse + // (unasserted) which tells the AT93C46 to signal when the write is + // complete. It does this by raising MISO, so we poll for this by + // transceiving chunks of 10 dummy bytes until we receive a non-zero bit. + writeComplete = 0; + bytesToTransceive = 10; + memset(command, 0, 10); // All zero, so EEPROM won't see a start-bit + for (i = 0; !writeComplete && i < 1000; i++) + { + ft4222Status = FT4222_SPIMaster_SingleReadWrite( + ftHandle, + response, + command, + bytesToTransceive, + &bytesTransceived, + FALSE); // keep slave-select asserted + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPIMaster_SingleReadWrite failed (error %d)!\n", + ft4222Status); + success = 0; + break; + } + + if (bytesTransceived != bytesToTransceive) + { + printf("FT4222_SPIMaster_SingleReadWrite " + "transceived %u bytes instead of %u.\n", + bytesTransceived, + bytesToTransceive); + success = 0; + break; + } + + for (j = 0; j < 10; j++) + { + if (response[j] != 0) + { + writeComplete = 1; + break; + } + } + } + + if (!writeComplete) + { + printf("AT93C46 did not confirm that the write completed.\n"); + success = 0; + } + + // Extra dummy write to de-assert slave-select. + (void)FT4222_SPIMaster_SingleReadWrite( + ftHandle, + response, + command, + 1, + &bytesTransceived, + TRUE); // de-assert slave-select afterwards. + +exit: + return success; +} + + + +/** + * Read a byte from the specified EEPROM address. + * + * @param ftHandle Handle of open FT4222. + * @param address EEPROM-internal memory location (7 bits). + * @param data Receives copy of 8-bit data stored at address. + * + * @return 1 for success, 0 for failure. + */ +static int eeprom_read(FT_HANDLE ftHandle, + const uint8 address, + uint8 *data) +{ + FT4222_STATUS ft4222Status; + int success = 1; + uint16 bytesToTransceive; + uint16 bytesTransceived; + uint8 command[4] = {0x03, 0x00, 0x00, 0x00}; + uint8 response[4] = {42, 42, 42, 42}; + uint8 result = 0; + + // Start bit (1) + opcode (10) + address to read, all padded with + // leading zeroes to make a multiple of 8 bits. + command[1] |= address; + + bytesToTransceive = 4; + + ft4222Status = FT4222_SPIMaster_SingleReadWrite( + ftHandle, + response, + command, + bytesToTransceive, + &bytesTransceived, + TRUE); // de-assert slave-select afterwards + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPIMaster_SingleReadWrite failed (error %d)!\n", + ft4222Status); + success = 0; + goto exit; + } + + if (bytesTransceived != bytesToTransceive) + { + printf("FT4222_SPIMaster_SingleReadWrite " + "transceived %u bytes instead of %u.\n", + bytesTransceived, + bytesToTransceive); + success = 0; + goto exit; + } + + // Value read from EEPROM is in bits 0 to 6 of byte 2, plus + // bit 7 of byte 3 + result = (response[2] << 1) & 0xFE; // byte 2, bits 0 to 6 + result |= (response[3] >> 7) & 0x01; // byte 3, bit 1 + + *data = result; + +exit: + return success; +} + + + +static int exercise4222(DWORD locationId) +{ + int success = 0; + FT_STATUS ftStatus; + FT_HANDLE ftHandle = (FT_HANDLE)NULL; + FT4222_STATUS ft4222Status; + FT4222_Version ft4222Version; + uint8 address; + char *writeBuffer; + + ftStatus = FT_OpenEx((PVOID)(uintptr_t)locationId, + FT_OPEN_BY_LOCATION, + &ftHandle); + if (ftStatus != FT_OK) + { + printf("FT_OpenEx failed (error %d)\n", + (int)ftStatus); + goto exit; + } + + ft4222Status = FT4222_GetVersion(ftHandle, + &ft4222Version); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_GetVersion failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + printf("Chip version: %08X, LibFT4222 version: %08X\n", + (unsigned int)ft4222Version.chipVersion, + (unsigned int)ft4222Version.dllVersion); + + // Configure the FT4222 as an SPI Master. + ft4222Status = FT4222_SPIMaster_Init( + ftHandle, + SPI_IO_SINGLE, // 1 channel + CLK_DIV_32, // 60 MHz / 32 == 1.875 MHz + CLK_IDLE_LOW, // clock idles at logic 0 + CLK_LEADING, // data captured on rising edge + SLAVE_SELECT(0)); // Use SS0O for slave-select + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPIMaster_Init failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + ft4222Status = FT4222_SPI_SetDrivingStrength(ftHandle, + DS_8MA, + DS_8MA, + DS_8MA); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPI_SetDrivingStrength failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + // First read original content + memset(originalContent, '!', EEPROM_BYTES); + + for (address = 0; address < EEPROM_BYTES; address++) + { + if (!eeprom_read(ftHandle, address, &originalContent[address])) + { + printf("Failed to read address %02X.\n", + (unsigned int)address); + // Failed, but keep trying subsequent addresses. + } + } + + if (0 != memcmp(originalContent, slogan1, EEPROM_BYTES)) + writeBuffer = slogan1; + else + writeBuffer = slogan2; + + if (!eeprom_enable_writes(ftHandle)) + { + printf("Failed to enable EEPROM writes.\n"); + goto exit; + } + + for (address = 0; address < EEPROM_BYTES; address++) + { + if (!eeprom_write(ftHandle, address, writeBuffer[address])) + { + printf("Failed to write to address %02X.\n", + (unsigned int)address); + // Failed, but keep trying subsequent addresses. + } + } + + memset(newContent, '!', EEPROM_BYTES); + + for (address = 0; address < EEPROM_BYTES; address++) + { + if (!eeprom_read(ftHandle, address, &newContent[address])) + { + printf("Failed to read address %02X.\n", + (unsigned int)address); + // Failed, but keep trying subsequent addresses. + } + } + + printf("\nOriginal content of EEPROM:\n"); + hexdump(originalContent, EEPROM_BYTES); + + printf("\nNew content of EEPROM:\n"); + hexdump(newContent, EEPROM_BYTES); + + success = 1; + +exit: + if (ftHandle != (FT_HANDLE)NULL) + { + (void)FT4222_UnInitialize(ftHandle); + (void)FT_Close(ftHandle); + } + + return success; +} + + +static int testFT4222(void) +{ + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo = NULL; + DWORD numDevs = 0; + int i; + int retCode = 0; + + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) + { + printf("FT_CreateDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -10; + goto exit; + } + + if (numDevs == 0) + { + printf("No devices connected.\n"); + retCode = -20; + goto exit; + } + + /* Allocate storage */ + devInfo = calloc((size_t)numDevs, + sizeof(FT_DEVICE_LIST_INFO_NODE)); + if (devInfo == NULL) + { + printf("Allocation failure.\n"); + retCode = -30; + goto exit; + } + + /* Populate the list of info nodes */ + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus != FT_OK) + { + printf("FT_GetDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -40; + goto exit; + } + + for (i = 0; i < (int)numDevs; i++) + { + if (devInfo[i].Type == FT_DEVICE_4222H_3) + { + printf("\nDevice %d is FT4222H in mode 3 (single Master or Slave):\n",i); + printf(" 0x%08x %s %s\n", + (unsigned int)devInfo[i].ID, + devInfo[i].SerialNumber, + devInfo[i].Description); + (void)exercise4222(devInfo[i].LocId); + break; + } + } + +exit: + free(devInfo); + return retCode; +} + +int main(void) +{ + return testFT4222(); +} + diff --git a/linux/examples/spis.c b/linux/examples/spis.c new file mode 100755 index 0000000..dd7dca5 --- /dev/null +++ b/linux/examples/spis.c @@ -0,0 +1,328 @@ +/* FT4222H SPI Slave example. + * + * Receive bytes from SPI Master, then process and return them. + * + * Windows build instructions: + * 1. Copy ftd2xx.h and 32-bit ftd2xx.lib from driver package. + * 2. Build. + * MSVC: cl spis.c LibFT4222.lib ftd2xx.lib + * MinGW: gcc spis.c LibFT4222.lib ftd2xx.lib + * + * Linux instructions: + * 1. Ensure libft4222.so is in the library search path (e.g. /usr/local/lib) + * 2. gcc spis.c -lft4222 -Wl,-rpath,/usr/local/lib + * 3. sudo ./a.out + * + * Mac instructions: + * 1. Ensure libft4222.dylib is in the library search path (e.g. /usr/local/lib) + * 2. gcc spis.c -lft4222 -Wl,-L/usr/local/lib + * 3. ./a.out + */ +#include +#include +#include +#include +#include +#include "ftd2xx.h" +#include "libft4222.h" + +#ifndef _countof + #define _countof(a) (sizeof((a))/sizeof(*(a))) +#endif + +#define BYTES_EXPECTED 128 // Length of Master's message. + +static uint8 rxBuffer[BYTES_EXPECTED]; + +#ifndef _WIN32 +#include + +static void Sleep(DWORD dwMilliseconds) +{ + struct timespec ts; + + ts.tv_sec = (time_t)dwMilliseconds / (time_t)1000; + ts.tv_nsec = ((long int)dwMilliseconds % 1000L) * 1000000L; + + (void)nanosleep(&ts, NULL); +} +#endif // _WIN32 + + + +static void hexdump(uint8 *address, uint16 length) +{ + char buf[3*8 + 2 + 8 + 1]; + char subString[4]; + int f; + int offsetInLine = 0; + char printable; + char unprinted = 0; + + buf[0] = '\0'; + + for (f = 0; f < length; f++) + { + offsetInLine = f % 8; + + if (offsetInLine == 0) + { + // New line. Display previous line... + printf("%s\n%p: ", buf, address + f); + unprinted = 0; + // ...and clear buffer ready for the new line. + memset(buf, (int)' ', sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + + sprintf(subString, "%02x ", (unsigned int)address[f]); + memcpy(&buf[offsetInLine * 3], subString, 3); + + if ( isprint((int)address[f]) ) + printable = (char)address[f]; + else + printable = '.'; + sprintf(subString, "%c", printable); + memcpy(&buf[3*8 + 2 + offsetInLine], subString, 1); + + unprinted++; // Remember + } + + if (unprinted) + printf("%s\n", buf); + + printf("\n"); +} + + + +static int exercise4222(DWORD locationId) +{ + int success = 0; + FT_STATUS ftStatus; + FT_HANDLE ftHandle = (FT_HANDLE)NULL; + FT4222_STATUS ft4222Status; + FT4222_Version ft4222Version; + uint16 bytesReceived = 0; + uint16 bytesWritten = 0; + int tries; + const int retryLimit = 321123456; // tune for your hardware + int i; + + ftStatus = FT_OpenEx((PVOID)(uintptr_t)locationId, + FT_OPEN_BY_LOCATION, + &ftHandle); + if (ftStatus != FT_OK) + { + printf("FT_OpenEx failed (error %d)\n", + (int)ftStatus); + goto exit; + } + + ft4222Status = FT4222_GetVersion(ftHandle, + &ft4222Version); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_GetVersion failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + printf("Chip version: %08X, LibFT4222 version: %08X\n", + (unsigned int)ft4222Version.chipVersion, + (unsigned int)ft4222Version.dllVersion); + + // Configure the FT4222 as SPI Slave. + ft4222Status = FT4222_SPISlave_Init(ftHandle); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPISlave_Init failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + // Wait for FT4222H to receive a MASTER_TRANSFER. + for (tries = 0; tries < retryLimit; tries++) + { + uint16 bytesAvailable = 0; + uint16 bytesRead = 0; + + ft4222Status = FT4222_SPISlave_GetRxStatus(ftHandle, + &bytesAvailable); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPISlave_GetRxStatus failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + if (bytesAvailable == 0) + continue; + + ft4222Status = FT4222_SPISlave_Read(ftHandle, + rxBuffer, + bytesAvailable, + &bytesRead); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPISlave_Read failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + bytesReceived += bytesRead; + + if (bytesReceived >= BYTES_EXPECTED) + break; // Message complete + } + + printf("\nReceived %u bytes from Master:\n", bytesReceived); + hexdump(rxBuffer, BYTES_EXPECTED); + + // Convert message to upper-case, then write it to Master. + for (i = 0; i < BYTES_EXPECTED; i++) + { + rxBuffer[i] = toupper(rxBuffer[i]); + } + +#ifdef VERIFY_CHECKSUM +{ + uint16 checksum = 0x5a + 0x81 + BYTES_EXPECTED; + + for (i = 0; i < BYTES_EXPECTED; i++) + { + checksum += rxBuffer[i]; + } + + printf("Checksum: %04X\n", checksum); +} +#endif // VERIFY_CHECKSUM + + // On Windows 8.1, libft4222 seems to need this delay to make the + // FT4222H actually send the following Slave_Write's data to the + // Master. Sleep(0) is not sufficient. + Sleep(1000); + + // Pass raw data to libFT4222, which will insert it into a + // SLAVE_TRANSFER command (header, data, checksum) to be read + // by the SPI Master. + ft4222Status = FT4222_SPISlave_Write(ftHandle, + rxBuffer, + BYTES_EXPECTED, + &bytesWritten); + if (FT4222_OK != ft4222Status) + { + printf("FT4222_SPISlave_Write failed (error %d)\n", + (int)ft4222Status); + goto exit; + } + + printf("FT4222_SPISlave_Write wrote %u (of %u) bytes.\n\n", + bytesWritten, + BYTES_EXPECTED); + + if (bytesWritten != BYTES_EXPECTED) + goto exit; + + success = 1; + + // The FT4222H probably has our data now. This delay keeps the + // FT4222H in SPI Slave mode long enough for the Master to read + // the entire SLAVE_TRANSFER. + Sleep(1000); + +exit: + if (ftHandle != (FT_HANDLE)NULL) + { + (void)FT4222_UnInitialize(ftHandle); + (void)FT_Close(ftHandle); + } + + return success; +} + + +static int testFT4222(void) +{ + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo = NULL; + DWORD numDevs = 0; + int i; + int retCode = 0; + int found = 0; + + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) + { + printf("FT_CreateDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -10; + goto exit; + } + + if (numDevs == 0) + { + printf("No devices connected.\n"); + retCode = -20; + goto exit; + } + + /* Allocate storage */ + devInfo = calloc((size_t)numDevs, + sizeof(FT_DEVICE_LIST_INFO_NODE)); + if (devInfo == NULL) + { + printf("Allocation failure.\n"); + retCode = -30; + goto exit; + } + + /* Populate the list of info nodes */ + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus != FT_OK) + { + printf("FT_GetDeviceInfoList failed (error code %d)\n", + (int)ftStatus); + retCode = -40; + goto exit; + } + + for (i = 0; i < (int)numDevs; i++) + { + if (devInfo[i].Type == FT_DEVICE_4222H_3) + { + printf("\nDevice %d is FT4222H in mode 3 (single Master or Slave):\n",i); + printf(" 0x%08x %s %s\n", + (unsigned int)devInfo[i].ID, + devInfo[i].SerialNumber, + devInfo[i].Description); + (void)exercise4222(devInfo[i].LocId); + found = 1; + break; + } + + if (devInfo[i].Type == FT_DEVICE_4222H_0) + { + printf("\nDevice %d is FT4222H in mode 0\n", i); + } + + if (devInfo[i].Type == FT_DEVICE_4222H_1_2) + { + printf("\nDevice %d is FT4222H in mode 1 or 2\n", i); + } + } + + if (!found) + printf("No mode-3 FT4222H device found.\n"); + +exit: + free(devInfo); + printf("Returning %d\n", retCode); + return retCode; +} + +int main(void) +{ + return testFT4222(); +} + diff --git a/linux/install4222.sh b/linux/install4222.sh new file mode 100755 index 0000000..31d6dfe --- /dev/null +++ b/linux/install4222.sh @@ -0,0 +1,43 @@ +# Install libft4222 and headers into /usr/local, so run using sudo! + +if [ "$(id -u)" != "0" ] ; then + echo "You must run this script with sudo." + exit 1 +fi + +unamem=$(uname -m) + +case "$unamem" in + x86_64) platform="x86_64" + ;; + i386 | i686) platform="i386" + ;; + armv6*) platform="arm-v6-hf" + ;; + armv7* ) platform="arm-v7-hf" + ;; + armv8* | aarch64 ) platform="arm-v8" + ;; + *) echo "Libft4222 is not currently supported on '$unamem'." + exit 1 + ;; +esac + +# Inside libft4222.tgz are release/32 and release/64 directories. +pathToLib=$(ls build-$platform/libft4222.so.*) +# echo "Found $pathToLib" +Lib=$(basename $pathToLib) +echo "Copying $pathToLib to /usr/local/lib" +yes | cp "$pathToLib" /usr/local/lib + +# Remove any existing symlink for libft4222 +rm -f /usr/local/lib/libft4222.so +ln -sf /usr/local/lib/$Lib /usr/local/lib/libft4222.so +ls -l /usr/local/lib/libft4222* + +echo "Copying headers to /usr/local/include" +cp libft4222.h /usr/local/include +cp ftd2xx.h /usr/local/include +cp WinTypes.h /usr/local/include +ls -l /usr/local/include/*.h + diff --git a/setup.py b/setup.py index fdb08d0..eac704b 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ elif machine() == 'i386': libdir = "linux/build-i386" elif machine() == 'armv7l': - libdir = "linux/build-arm-v7" + libdir = "linux/build-arm-v7-hf" elif machine().startswith("arm"): if architecture()[0] == '64bit': libdir = "linux/build-arm-v8"