l29ah / libmpsse

(a maintenance fork of the) Open source library for SPI/I2C control via FTDI chips

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SPI transfers fail once clock rate is set higher than 6Mhz

stephendpmurphy opened this issue Β· comments

Hi there πŸ‘‹ First off, thank you for all of your work in updating and maintaining this lib. It's been easy to integrate and I appreciate the open-source aspect of it.

However, I am having some issues. I am integrating this lib into my C application and attempting to send SPI communications with a FT2232HL bridge and verifying the output using a Salae Logic analyzer. My issues are as follows

  • SPI Writes give what just looks like erratic bouncing lines (Actually very similar results to my next issue) - I have had to replace my Writes with a Transfer call in order for it to work properly
  • SPI transactions (Read/Write/Transfer) can not exceed 6Mhz. Otherwise the IO lines appear erratic and unpredictable.

Below is a snippet of the code used to initiate a transfer. The _write function opens up the channel with our SPI configuration retrieved from my defined xfer_t which then calls the spi_write function where the transfer is actually initiated and then cleaned up.

void SPI::_write(shost_xfer_t *xfer) {
    int ret = 0;
    // Open an MPSSE instance for SPI0 and store the context
    this->mpsse = MPSSE(modes::SPI0, xfer->clk, MSB);

    // Ensure the context is not NULL and and the mpsse channel is open
    if (this->mpsse != NULL && !this->mpsse->open) {
        // TODO what should be something like: "Failed to initialize MPSSE: %s\n", ErrorString(this->mpsse)
        throw std::system_error(EIO, std::generic_category(), ErrorString(this->mpsse));
    }

    ret = spi_write(xfer->buff, xfer->len);

    Close(this->mpsse);

    switch (ret) {
        case 1:
            // TODO printing address whould be nice
            throw std::system_error(ENXIO, std::generic_category(), "No response from peripheral.");
            break;
        case 2:
            throw std::system_error(EIO, std::generic_category(), "Hardware failure.");
            break;
        default:
            // all is good, no need to do anything.
            break;
    }
    xfer->bytesTranferred = xfer->len;
}

int8_t SPI::spi_write(uint8_t *src_buffer, size_t buffer_len) {
    int8_t retVal = 0;
    char *writeBuffer = (char *) malloc(buffer_len);
    char *readBuffer = (char *) malloc(buffer_len+1);
    memcpy((void*)writeBuffer, (const void*)src_buffer, buffer_len);

    // Send the start condition for SPI
    if( MPSSE_OK != Start(mpsse) ) {
        retVal = 1;
        goto CLEANUP;
    }
    // Write our buffer
    readBuffer = Transfer(mpsse, writeBuffer, buffer_len);
    // Send the stop condition for SPI
    Stop(mpsse);

CLEANUP:
    // Free the write buffer we created
    free(writeBuffer);
    free(readBuffer);

    return retVal;
}

Here is a preview of a Read transaction at what is supposed to be 12Mhz.
shost_failedTransfer_12Mhz

1.) As a sanity check, do you see anything off in the transfer code.
2.) Have you seen related issues to pushing the clock rate too far on certain hardware?