Created
February 16, 2025 16:36
-
-
Save jpf91/ac1fd5520de84268b96a93eaa434a271 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // 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