-
-
Save ahmetserdar/4240ddc505e49d0c70797e27e173aa47 to your computer and use it in GitHub Desktop.
FTDI GPIO example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <iomanip> | |
#include <chrono> // for std::chrono::milliseconds | |
#include <thread> // for std::this_thread::sleep_for | |
#include "ftd2xx.h" // must be in project include path | |
/*** HELPER FUNCTION DECLARATIONS ***/ | |
// Formats and writes FT_DEVICE_LIST_INFO_NODE structure to output | |
// stream object. | |
std::ostream& operator<<(std::ostream& os, const FT_DEVICE_LIST_INFO_NODE& device); | |
// Prints a formatted error message and terminates the program with | |
// status code EXIT_FAILURE. | |
void error(const char* message); | |
// Prints FT_STATUS and a formatted error message and terminates | |
// the program with status code EXIT_FAILURE. | |
void ft_error(FT_STATUS status, const char* message); | |
// Prints FT_STATUS and a formatted error message, closes `handle`, | |
// and terminates the program with status code EXIT_FAILURE. | |
// (Delegates to ft_error(FT_STATUS, const char*)) | |
void ft_error(FT_STATUS status, const char* message, FT_HANDLE handle); | |
/*** MAIN PROGRAM ***/ | |
int main() | |
{ | |
FT_STATUS status; | |
// --- Get number of devices --- | |
unsigned long deviceCount = 0; | |
status = FT_CreateDeviceInfoList(&deviceCount); | |
if (status != FT_OK) { | |
ft_error(status, "FT_CreateDeviceInfoList"); | |
} | |
if (deviceCount == 0) { | |
error("No FTDI devices found."); | |
} | |
// --- Enumerate devices --- | |
FT_DEVICE_LIST_INFO_NODE* deviceInfos = new FT_DEVICE_LIST_INFO_NODE[deviceCount]; | |
status = FT_GetDeviceInfoList(deviceInfos, &deviceCount); | |
// ... populates deviceInfos array | |
if (status != FT_OK) { | |
ft_error(status, "FT_GetDeviceInfoList"); | |
} | |
// --- Find device of interest --- | |
const unsigned long myID = 0x04036014; | |
// ... from "Device Manager": Vendor ID = 0403, Product ID = 6014 | |
FT_DEVICE_LIST_INFO_NODE myDevice{}; | |
// Find first device that matches `myID` | |
for (unsigned int i = 0; i < deviceCount; i++) | |
{ | |
if (deviceInfos[i].ID == myID) | |
{ | |
// Copy device info into `myDevice` | |
myDevice = deviceInfos[i]; | |
// Open device | |
status = FT_Open(i, &myDevice.ftHandle); | |
if (status != FT_OK) { | |
ft_error(status, "FT_Open"); | |
} | |
break; | |
} | |
} | |
// Handle device not found... | |
if (myDevice.ID != myID) | |
{ | |
std::cerr << "0 of " << deviceCount << " devices with ID " << std::hex << std::showbase << myID << " found:\n"; | |
for (unsigned int i = 0; i < deviceCount; i++) | |
{ | |
std::cerr << "Device " << i << "\n"; | |
std::cerr << deviceInfos[i] << std::endl; | |
} | |
error("Device not found."); | |
} | |
std::cout << "Device found with ID " << std::hex << std::showbase << myID << ":\n"; | |
std::cout << myDevice << std::endl; | |
// Clean up device info list | |
delete[] deviceInfos; | |
// --- Set up command buffers --- | |
uint8_t recvBuffer[1024] = { 0 }; | |
unsigned long bytesWritten = 0; | |
unsigned long bytesRead = 0; | |
// --- Configure Port for MPSSE --- | |
// This procedure comes from FTDI application note | |
// "AN 135 - MPSSE Basics", "Section 4. Software Configuration". | |
// It's not clear yet if all steps are required for Lab 3, but | |
// Lab 3 works having followed these steps. | |
// - Jon | |
// Reset device | |
status = FT_ResetDevice(myDevice.ftHandle); | |
if (status != FT_OK) { | |
ft_error(status, "FT_ResetDevice", myDevice.ftHandle); | |
} | |
// Set USB transfer sizes | |
status = FT_SetUSBParameters(myDevice.ftHandle, 64, 64); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetUSBParameters", myDevice.ftHandle); | |
} | |
// Disable error characters | |
status = FT_SetChars(myDevice.ftHandle, 0, 0, 0, 0); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetChars", myDevice.ftHandle); | |
} | |
// Set device read/write timeouts | |
status = FT_SetTimeouts(myDevice.ftHandle, 1000, 1000); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetTimeouts", myDevice.ftHandle); | |
} | |
// Set timeout before flushing receive buffer | |
status = FT_SetLatencyTimer(myDevice.ftHandle, 10); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetLatencyTimer", myDevice.ftHandle); | |
} | |
// Disable flow control | |
status = FT_SetFlowControl(myDevice.ftHandle, FT_FLOW_NONE, 0, 0); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetFlowControl", myDevice.ftHandle); | |
} | |
// Reset MPSSE controller | |
status = FT_SetBitMode(myDevice.ftHandle, 0, 0); | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetBitMode", myDevice.ftHandle); | |
} | |
// Initialize MPSSE controller | |
status = FT_SetBitMode(myDevice.ftHandle, 0xFF, 0x02); // All pins outputs, MPSSE | |
if (status != FT_OK) { | |
ft_error(status, "FT_SetBitMode", myDevice.ftHandle); | |
} | |
// --- Test bad command detection --- | |
/* TODO */ | |
// --- Configure MPSSE --- | |
/* TODO */ | |
// --- Write commands --- | |
// * iterate through 0x00 to 0xFF and output value on AD[7:0] every 100ms | |
uint8_t gpio_command[] = { 0x80, 0x00, 0xFF }; | |
// 0x80: Command to set AD[7:0]. | |
// 0x00: Output values for AD[7:0] (placeholder) | |
// 0xFF: GPIO directions for AD[7:0] (1 = output) | |
uint8_t value = 0; | |
// Infinite loop | |
while (true) | |
{ | |
gpio_command[1] = value; // Set value | |
std::cout << "\rWriting: " << std::noshowbase << std::hex << std::setfill('0') << std::setw(2) << int(value); | |
status = FT_Write(myDevice.ftHandle, gpio_command, sizeof(gpio_command), &bytesWritten); | |
if (status != FT_OK) { | |
ft_error(status, "FT_Write", myDevice.ftHandle); | |
} | |
if (bytesWritten != sizeof(gpio_command)) { | |
error("Error while writing to device."); | |
} | |
// Sleep thread | |
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | |
value++; | |
value &= 0x0F; | |
} | |
return 0; | |
} | |
/*** HELPER FUNCTION DEFINITIONS ***/ | |
void error(const char* message) | |
{ | |
std::cerr << "\033[1;31m[ERROR]\033[0m " << message << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
void ft_error(FT_STATUS status, const char* message) | |
{ | |
std::cerr << "\033[1;31m[ERROR]\033[0m " << message << ": " << status << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
void ft_error(FT_STATUS status, const char* message, FT_HANDLE handle) | |
{ | |
FT_Close(handle); | |
ft_error(status, message); | |
} | |
std::ostream& operator<<(std::ostream& os, const FT_DEVICE_LIST_INFO_NODE& device) | |
{ | |
os << " @" << std::showbase << std::hex << &device << "\n"; | |
os << " Flags=" << std::showbase << std::hex << device.Flags << "\n"; | |
os << " Type=" << std::showbase << std::hex << device.Type << "\n"; | |
os << " ID=" << std::showbase << std::hex << device.ID << "\n"; | |
os << " LocId=" << std::showbase << std::hex << device.LocId << "\n"; | |
os << " SerialNumber=" << device.SerialNumber << "\n"; | |
os << " Description=" << device.Description << "\n"; | |
os << " ftHandle=" << std::showbase << std::hex << device.ftHandle << "\n"; | |
return os; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment