internal void SpiInitialize() { // Do we already have SPI setup? if (IsSpiModeEnabled) { // No need to initialize everything return; } GetHandle(); IsSpiModeEnabled = true; var ftStatus = FtFunction.FT_SetLatencyTimer(_ftHandle, 1); ftStatus = FtFunction.FT_SetUSBParameters(_ftHandle, 65535, 65535); ftStatus = FtFunction.FT_SetChars(_ftHandle, 0, 0, 0, 0); ftStatus = FtFunction.FT_SetTimeouts(_ftHandle, 3000, 3000); ftStatus = FtFunction.FT_SetLatencyTimer(_ftHandle, 1); // Reset ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x00); // Enable MPSSE mode ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x02); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to setup device {Description}, status: {ftStatus} in MPSSE mode"); } // 50 ms according to thr doc for all USB to complete Thread.Sleep(50); DiscardInput(); SetupMpsseMode(); int idx = 0; Span <byte> toSend = stackalloc byte[10]; toSend[idx++] = (byte)FtOpcode.DisableClockDivideBy5; toSend[idx++] = (byte)FtOpcode.TurnOffAdaptativeClocking; toSend[idx++] = (byte)FtOpcode.Disable3PhaseDataClocking; toSend[idx++] = (byte)FtOpcode.SetDataBitsLowByte; // Pin clock output, MISO output, MOSI input GpioLowDir = (byte)((GpioLowDir & 0xF8) | 0x03); // clock, MOSI and MISO to 0 GpioLowData = (byte)(GpioLowData & 0xF8); toSend[idx++] = GpioLowDir; toSend[idx++] = GpioLowData; // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off // TCK period = 60MHz / (( 1 + [ (0xValueH * 256) OR 0xValueL] ) * 2) // Command to set clock divisor toSend[idx++] = (byte)FtOpcode.SetClockDivisor; uint clockDivisor = (uint)(60000 / ((ConnectionSettings[0].ClockFrequency / 1000) * 2) - 1); toSend[idx++] = (byte)(clockDivisor & 0xFF); toSend[idx++] = (byte)(clockDivisor >> 8); // loopback off toSend[idx++] = (byte)FtOpcode.DisconnectTDItoTDOforLoopback; Write(toSend); // Delay as in the documentation Thread.Sleep(30); }
/// <inheritdoc/> public void Reset() { var ftStatus = FtFunction.FT4222_I2CMaster_Reset(FtHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to reset: {ftStatus}"); } }
/// <inheritdoc/> public void WriteEx(int slaveAddress, I2cMasterFlags flags, ReadOnlySpan <byte> buffer) { var ftStatus = FtFunction.FT4222_I2CMaster_WriteEx(FtHandle, (ushort)slaveAddress, (byte)flags, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out _); if (ftStatus != FtStatus.Ok) { throw new IOException($"{nameof(WriteEx)} failed to write, error: {ftStatus}"); } }
/// <inheritdoc/> public void ReadEx(int slaveAddress, I2cMasterFlags flags, Span <byte> buffer) { var result = FtFunction.FT4222_I2CMaster_ReadEx(FtHandle, (ushort)slaveAddress, (byte)flags, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out _); if (result != FtStatus.Ok) { throw new IOException(); } }
/// <inheritdoc/> public void Read(int slaveAddress, Span <byte> buffer) { var ftStatus = FtFunction.FT4222_I2CMaster_Read(FtHandle, (ushort)slaveAddress, in MemoryMarshal.GetReference(buffer), (ushort)buffer.Length, out _); if (ftStatus != FtStatus.Ok) { throw new IOException($"{nameof(Read)} failed to read, error: {ftStatus}"); } }
/// <inheritdoc/> public byte GetStatus() { var ftStatus = FtFunction.FT4222_I2CMaster_GetStatus(FtHandle, out var controllerStatus); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to get status: {ftStatus}"); } return(controllerStatus); }
/// <inheritdoc/> public FtVersion GetVersionValues() { var ftStatus = FtFunction.FT4222_GetVersion(FtHandle, out var ftVersion); if (ftStatus != FtStatus.Ok) { throw new IOException($"Can't find versions of chipset and FT4222, status: {ftStatus}"); } return(ftVersion); }
internal void GetHandle() { if ((_ftHandle == null) || _ftHandle.IsClosed) { // Open device if not opened var ftStatus = FtFunction.FT_OpenEx(LocId, FtOpenType.OpenByLocation, out _ftHandle); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to open device {Description}, status: {ftStatus}"); } } }
internal void InitializeGpio() { if (IsI2cModeEnabled || IsSpiModeEnabled) { return; } // Reset var ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x00); // Enable MPSSE mode ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x02); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to setup device {Description}, status: {ftStatus} in MPSSE mode"); } // 50 ms according to thr doc for all USB to complete Thread.Sleep(50); DiscardInput(); SetupMpsseMode(); }
internal void I2cInitialize() { GetHandle(); // check is any of the first 3 GPIO are open if (PinOpen[0] || PinOpen[1] || PinOpen[2]) { throw new IOException("Can't open I2C if GPIO 0, 1 or 2 are open"); } if (IsSpiModeEnabled) { throw new IOException("Can't open I2C if SPI mode is used"); } var ftStatus = FtFunction.FT_SetTimeouts(_ftHandle, 5000, 5000); ftStatus = FtFunction.FT_SetLatencyTimer(_ftHandle, 16); ftStatus = FtFunction.FT_SetFlowControl(_ftHandle, (ushort)FtFlowControl.FT_FLOW_RTS_CTS, 0x00, 0x00); ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x00); ftStatus = FtFunction.FT_SetBitMode(_ftHandle, 0x00, 0x02); if (ftStatus != FtStatus.Ok) { throw new IOException($"Failed to setup device {Description}, status: {ftStatus} in MPSSE mode"); } IsI2cModeEnabled = true; DiscardInput(); SetupMpsseMode(); // Now setup the clock and other elements Span <byte> toSend = stackalloc byte[13]; int idx = 0; // Disable clock divide by 5 for 60Mhz master clock toSend[idx++] = (byte)FtOpcode.DisableClockDivideBy5; // Turn off adaptive clocking toSend[idx++] = (byte)FtOpcode.TurnOffAdaptativeClocking; // Enable 3 phase data clock, used by I2C to allow data on both clock edges toSend[idx++] = (byte)FtOpcode.Enable3PhaseDataClocking; // The SK clock frequency can be worked out by below algorithm with divide by 5 set as off // TCK period = 60MHz / (( 1 + [ (0xValueH * 256) OR 0xValueL] ) * 2) // Command to set clock divisor toSend[idx++] = (byte)FtOpcode.SetClockDivisor; uint clockDivisor = 60000 / (I2cMasterFrequencyKbps * 2) - 1; toSend[idx++] = (byte)(clockDivisor & 0x00FF); toSend[idx++] = (byte)((clockDivisor >> 8) & 0x00FF); // loopback off toSend[idx++] = (byte)FtOpcode.DisconnectTDItoTDOforLoopback; // Enable the FT232H's drive-zero mode with the following enable mask toSend[idx++] = (byte)FtOpcode.SetIOOnlyDriveOn0AndTristateOn1; // Low byte (ADx) enables - bits 0, 1 and 2 toSend[idx++] = 0x07; // High byte (ACx) enables - all off toSend[idx++] = 0x00; // Command to set directions of lower 8 pins and force value on bits set as output toSend[idx++] = (byte)FtOpcode.SetDataBitsLowByte; // SDA and SCL both output high (open drain) GpioLowData = (byte)(I2cDataSDAhiSCLhi | (GpioLowData & 0xF8)); GpioLowDir = (byte)(I2cDirSDAoutSCLout | (GpioLowDir & 0xF8)); toSend[idx++] = GpioLowData; toSend[idx++] = GpioLowDir; Write(toSend); }
private void Close() { FtFunction.FT4222_UnInitialize(FtHandle); FtFunction.FT_Close(FtHandle); }