Skip to content

Instantly share code, notes, and snippets.

@jpf91
Created February 16, 2025 16:36
Show Gist options
  • Select an option

  • Save jpf91/ac1fd5520de84268b96a93eaa434a271 to your computer and use it in GitHub Desktop.

Select an option

Save jpf91/ac1fd5520de84268b96a93eaa434a271 to your computer and use it in GitHub Desktop.
// Send 8 bit data to FPGA on Upduino via SPI
// See https://jpfau.org/blog/upduino-usb-spi/ for details and FPGA sample application.
// compile like this: g++ upduino_spi.cpp -o upduino_spi -lftdi1 `pkg-config libftdi1 --cflags`
#include <ftdi.h>
#include <unistd.h>
#include <stdexcept>
#include <string.h>
using std::string;
#define VENDOR 0x0403
#define PRODUCT 0x6014
// ADBUS0
#define PIN_SCK 0
// ADBUS1
#define PIN_MOSI 1
// ADBUS2
#define PIN_NSS 2
#define OUTPUT_PINMASK ((1 << PIN_SCK) | (1 << PIN_MOSI) | (1 << PIN_NSS))
void enforce(bool condition, string msg = "Enforcement failed")
{
if (!condition)
throw std::runtime_error(msg);
}
class SPIDriver
{
private:
struct ftdi_context _ftdi;
void setupMPSSE()
{
// 1 MHz, Disable adaptive and 3 phase clocking, set ADBUS all spi pins as output, nSS initial high
uint8_t buf[] = {TCK_DIVISOR, 0x05, 0x00,
DIS_ADAPTIVE,
DIS_3_PHASE,
SET_BITS_LOW, (1 << PIN_NSS), OUTPUT_PINMASK
};
// Write the setup to the chip.
enforce(ftdi_write_data(&_ftdi, buf, sizeof(buf)) == sizeof(buf), "FTDI setup failed");
}
public:
SPIDriver() {}
void open()
{
auto status = ftdi_init(&_ftdi);
enforce(status == 0, "Failed to initialize libftdi");
status = ftdi_usb_open(&_ftdi, VENDOR, PRODUCT);
enforce(status == 0, "Failed to open device: " + string(ftdi_get_error_string(&_ftdi)));
enforce(ftdi_usb_reset(&_ftdi) == 0, "ftdi_usb_reset failed");
enforce(ftdi_set_interface(&_ftdi, INTERFACE_ANY) == 0, "ftdi_set_interface failed");
enforce(ftdi_set_bitmode(&_ftdi, 0, 0) == 0, "ftdi_set_bitmode failed");
enforce(ftdi_set_bitmode(&_ftdi, 0, BITMODE_MPSSE) == 0, "ftdi_set_bitmode failed");
enforce(ftdi_tcioflush(&_ftdi) == 0, "ftdi_tcioflush failed");
usleep(50000);
setupMPSSE();
}
void writeData(uint8_t data)
{
uint8_t buf[] = {
SET_BITS_LOW, 0x00, OUTPUT_PINMASK,
MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 0x00, 0x00, data,
SET_BITS_LOW, (1 << PIN_NSS), OUTPUT_PINMASK
};
enforce(ftdi_write_data(&_ftdi, buf, sizeof(buf)) == sizeof(buf), "FTDI write failed");
}
void close()
{
ftdi_usb_reset(&_ftdi);
enforce(ftdi_usb_close(&_ftdi) == 0, "ftdi_usb_close failed");
}
};
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc != 9)
{
printf("Usage: upduino_spi 0 0 0 0 0 0 0\n");
return -1;
}
uint8_t data = 0;
for (size_t i = 0; i < 8; i++)
{
if (string(argv[1+i]) == "1")
data |= (1 << (7 - i));
}
auto dev = new SPIDriver();
dev->open();
dev->writeData(data);
dev->close();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment