Init_libMPSSE(),status = SPI_GetNumChannels(noChannels);总是返回0

时间:2018-04-14 07:55:30

标签: c driver ftdi

我使用的是FT2232H-56Q。我想使用SPI通道。我下载了the libMPSSE-SPI example

我正在使用示例示例" sample-static.c"。当我运行exe时,我总是收到这条消息:

  

按任意键继续。 。 。可用SPI通道数= 0

即使设备已连接,也会发生这种情况。

代码:

/*!
 * \file sample-static.c
 *
 * \author FTDI
 * \date 20110512
 *
 * Copyright © 2000-2014 Future Technology Devices International Limited
 *
 *
 * THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Project: libMPSSE
 * Module: SPI Sample Application - Interfacing 94LC56B SPI EEPROM
 *
 * Rivision History:
 * 0.1  - 20110512 - Initial version
 * 0.2  - 20110801 - Changed LatencyTimer to 255
 *                   Attempt to open channel only if available
 *                   Added & modified macros
 *                   Included stdlib.h
 * 0.3  - 20111212 - Added comments
 * 0.41 - 20140903 - Fixed compilation warnings
 *                   Added testing of SPI_ReadWrite()
 */

/******************************************************************************/
/*                           Include files                                         */
/******************************************************************************/
/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <assert.h>
//#include <vector.h>
#include <stdbool.h>
//#include <random>

/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif

/* Include D2XX header*/
#include "ftd2xx.h"

/* Include libMPSSE header */
#include "libMPSSE_spi.h"

/******************************************************************************/
/*                              Macro and type defines                             */
/******************************************************************************/
/* Helper macros */

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Application specific macro definations */
#define SPI_DEVICE_BUFFER_SIZE      256
#define SPI_WRITE_COMPLETION_RETRY      10
#define START_ADDRESS_EEPROM    0x00 /*read/write start address inside the EEPROM*/
#define END_ADDRESS_EEPROM      0x10
#define RETRY_COUNT_EEPROM      10  /* number of retries if read/write fails */
#define CHANNEL_TO_OPEN         0   /*0 for first available channel, 1 for next... */
#define SPI_SLAVE_0             0
#define SPI_SLAVE_1             1
#define SPI_SLAVE_2             2
#define DATA_OFFSET             4
#define USE_WRITEREAD           0

/******************************************************************************/
/*                              Global variables                                    */
/******************************************************************************/
static FT_HANDLE ftHandle;
static uint8 buffer[SPI_DEVICE_BUFFER_SIZE] = {0};
static FT_DEVICE_LIST_INFO_NODE *devList;
static uint32 numberChannels;
/******************************************************************************/
/*                      Public function definitions                                */
/******************************************************************************/

/**
* @brief Initializes the comBridge
* Must be called first
* @param[out] noChannels: Number of available channels
* @param[out] channelId[]: Description of the devices with their index being identical to the channel selector in all other functions
* @return Device status with FT_OK = 0
*/
FT_STATUS comBridge_initialize(uint32 *noChannels, char *channelId[]) {
    Init_libMPSSE();

    FT_STATUS status = FT_OK;

    // get number of channels
    status = SPI_GetNumChannels(noChannels);
    numberChannels = *noChannels;
    APP_CHECK_STATUS(status);
#ifdef VERBOSE
    printf("ComBridge initialized\n");
    printf("  SPI channels %d\n\n", *noChannels);
#endif // VERBOSE

    // get channel infos
    devList = (FT_DEVICE_LIST_INFO_NODE *)calloc(*noChannels, sizeof(FT_DEVICE_LIST_INFO_NODE));
    for (uint32 channelIndex = 0; channelIndex < *noChannels; channelIndex++) {
        status = SPI_GetChannelInfo(channelIndex, devList);
        APP_CHECK_STATUS(status);
        strcpy(channelId[channelIndex],  devList->Description);
#ifdef VERBOSE
        printf("Channel %d info\n", channelIndex);
        printf("  Flags        0x%x\n", devList->Flags);
        printf("  Type         0x%x\n", devList->Type);
        printf("  ID           0x%x\n", devList->ID);
        printf("  LocId        0x%x\n", devList->LocId);
        printf("  SerialNumber %s\n", devList->SerialNumber);
        printf("  Description  %s\n", devList->Description);
        //printf("  ftHandle=0x%x\n", (unsigned int)devList->ftHandle);
        printf("\n");
#endif // VERBOSE
    };
    return status;
}

/**
* @brief Opens and initilizes a SPI channel
* Must be called after comBridge_initialize() and for each channel individually
* Latency = 255 ms, that "xDBUS3 of MPSSE is chip select" and that "chip select is active high" are predefined and cannot be changed manually
* @param[in] channel: Selects a channel via the index of the corresponding element in the channelId[] array
* @param[in] clockRate_Hz: Clock rate of the SPI bus in Hz (0..10 MHz)
* @param[in] spiMode: Selects SPI Mode (SPI_CONFIG_OPTION_MODE0 or SPI_CONFIG_OPTION_MODE3)
* @return Device status with FT_OK = 0
*/
FT_STATUS comBridge_setup(uint32 channel, uint32 clockRate_Hz, uint32 spiMode) {
    FT_STATUS status = FT_OK;

    assert(channel < numberChannels);
    assert(clockRate_Hz <= 10000000);
    assert((spiMode == SPI_CONFIG_OPTION_MODE0) | (spiMode == SPI_CONFIG_OPTION_MODE3));

    status = SPI_OpenChannel(channel, &devList[channel].ftHandle);
    APP_CHECK_STATUS(status);

    ChannelConfig channelConf = {
        5000, // ClockRate
        255, // LatencyTime
        SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW, // configOptions
        0x00000000 // Pin
    };
    channelConf.ClockRate = clockRate_Hz;
    channelConf.configOptions = spiMode | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
    status = SPI_InitChannel(devList[channel].ftHandle, &channelConf);
    APP_CHECK_STATUS(status);

#ifdef VERBOSE
    printf("Channel %d opened\n", channel);
    printf("  ClockRate    %d\n", channelConf.ClockRate);
    printf("  Latency      %d\n", channelConf.LatencyTimer);
    printf("  Config       %d\n", channelConf.configOptions);
    printf("  Pin          %d\n\n", channelConf.Pin);
    //printf("  Handle=%ld\n", (uint32)devList[channel].ftHandle);
#endif // VERBOSE

    // sets all GPIO pins as input
    status = FT_WriteGPIO(devList[channel].ftHandle, 0b00000000, 0b00000000);
    APP_CHECK_STATUS(status);
    return status;
}


/*!
 * \brief Writes to EEPROM
 *
 * This function writes a byte to a specified address within the 93LC56B EEPROM
 *
 * \param[in] slaveAddress Address of the I2C slave (EEPROM)
 * \param[in] registerAddress Address of the memory location inside the slave to where the byte
 *          is to be written
 * \param[in] data The byte that is to be written
 * \return Returns status code of type FT_STATUS(see D2XX Programmer's Guide)
 * \sa Datasheet of 93LC56B http://ww1.microchip.com/downloads/en/DeviceDoc/21794F.pdf
 * \note
 * \warning
 */
static FT_STATUS read_byte(uint8 slaveAddress, uint8 address, uint16 *data)
{
    uint32 sizeToTransfer = 0;
    uint32 sizeTransfered;
    uint8 writeComplete=0;
    uint32 retry=0;
    FT_STATUS status;

    /* CS_High + Write command + Address */
    sizeToTransfer=1;
    sizeTransfered=0;
    buffer[0] = 0xC0;/* Write command (3bits)*/
    buffer[0] = buffer[0] | ( ( address >> 3) & 0x0F );/*5 most significant add bits*/
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
    APP_CHECK_STATUS(status);

    /*Write partial address bits */
    sizeToTransfer=4;
    sizeTransfered=0;
    buffer[0] = ( address & 0x07 ) << 5; /* least significant 3 address bits */
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS);
    APP_CHECK_STATUS(status);

    /*Read 2 bytes*/
    sizeToTransfer=2;
    sizeTransfered=0;
    status = SPI_Read(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
    APP_CHECK_STATUS(status);

    *data = (uint16)(buffer[1]<<8);
    *data = (*data & 0xFF00) | (0x00FF & (uint16)buffer[0]);

    return status;
}

/*!
 * \brief Reads from EEPROM
 *
 * This function reads a byte from a specified address within the 93LC56B EEPROM
 *
 * \param[in] slaveAddress Address of the I2C slave (EEPROM)
 * \param[in] registerAddress Address of the memory location inside the slave from where the
 *          byte is to be read
 * \param[in] *data Address to where the byte is to be read
 * \return Returns status code of type FT_STATUS(see D2XX Programmer's Guide)
 * \sa Datasheet of 93LC56B http://ww1.microchip.com/downloads/en/DeviceDoc/21794F.pdf
 * \note
 * \warning
 */
static FT_STATUS write_byte(uint8 slaveAddress, uint8 address, uint16 data)
{
    uint32 sizeToTransfer = 0;
    uint32 sizeTransfered=0;
    uint8 writeComplete=0;
    uint32 retry=0;
    FT_STATUS status;

    /* Write command EWEN(with CS_High -> CS_Low) */
    sizeToTransfer=11;
    sizeTransfered=0;
    buffer[0]=0x9F;/* SPI_EWEN -> binary 10011xxxxxx (11bits) */
    buffer[1]=0xFF;
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
    APP_CHECK_STATUS(status);

    /* CS_High + Write command + Address */
    sizeToTransfer=1;
    sizeTransfered=0;
    buffer[0] = 0xA0;/* Write command (3bits) */
    buffer[0] = buffer[0] | ( ( address >> 3) & 0x0F );/*5 most significant add bits*/
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
    APP_CHECK_STATUS(status);

    /*Write 3 least sig address bits */
    sizeToTransfer=3;
    sizeTransfered=0;
    buffer[0] = ( address & 0x07 ) << 5; /* least significant 3 address bits */
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS);
    APP_CHECK_STATUS(status);

    /* Write 2 byte data + CS_Low */
    sizeToTransfer=2;
    sizeTransfered=0;
    buffer[0] = (uint8)(data & 0xFF);
    buffer[1] = (uint8)((data & 0xFF00)>>8);
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
    APP_CHECK_STATUS(status);

    /* Wait until D0 is high */
#if 1
    /* Strobe Chip Select */
    sizeToTransfer=0;
    sizeTransfered=0;
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
    APP_CHECK_STATUS(status);
#ifndef __linux__
    Sleep(10);
#endif
    sizeToTransfer=0;
    sizeTransfered=0;
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
    APP_CHECK_STATUS(status);
#else
    retry=0;
    state=FALSE;
    SPI_IsBusy(ftHandle,&state);
    while((FALSE==state) && (retry<SPI_WRITE_COMPLETION_RETRY))
    {
        printf("SPI device is busy(%u)\n",(unsigned)retry);
        SPI_IsBusy(ftHandle,&state);
        retry++;
    }
#endif
    /* Write command EWEN(with CS_High -> CS_Low) */
    sizeToTransfer=11;
    sizeTransfered=0;
    buffer[0]=0x8F;/* SPI_EWEN -> binary 10011xxxxxx (11bits) */
    buffer[1]=0xFF;
    status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
        SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
        SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
    APP_CHECK_STATUS(status);
    return status;
}

/*!
 * \brief Main function / Entry point to the sample application
 *
 * This function is the entry point to the sample application. It opens the channel, writes to the
 * EEPROM and reads back.
 *
 * \param[in] none
 * \return Returns 0 for success
 * \sa
 * \note
 * \warning
 */
int main()
{
    uint32 noChannels = 0;
    char *channelId[10];
    char channelIdArray[10][46] = { { '\0' } };
    for (int i = 0; i < sizeof(channelId); i++)
        channelId[i] = channelIdArray[i];
    comBridge_initialize(&noChannels, channelId);
    for (uint32 channel = 0; channel < noChannels; channel++)
    {
        //cout << "Channel " << channel << ": " << channelId[channel] << endl;
        comBridge_setup(channel, 100000, SPI_CONFIG_OPTION_MODE0);

        comBridge_release(channel);
    }


    FT_STATUS status = FT_OK;
    FT_DEVICE_LIST_INFO_NODE devList = {0};
    ChannelConfig channelConf = {0};
    uint8 address = 0;
    uint32 channels = 0;
    uint16 data = 0;
    uint8 i = 0;
    uint8 latency = 255;    

    channelConf.ClockRate = 5000;
    channelConf.LatencyTimer = latency;
    channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3;// | SPI_CONFIG_OPTION_CS_ACTIVELOW;
    channelConf.Pin = 0x00000000;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/

    /* init library */
#ifdef _MSC_VER
    Init_libMPSSE();
#endif
    status = SPI_GetNumChannels(&channels);
    APP_CHECK_STATUS(status);
    printf("Number of available SPI channels = %d\n",(int)channels);

    if(channels>0)
    {
        for(i=0;i<channels;i++)
        {
            status = SPI_GetChannelInfo(i,&devList);
            APP_CHECK_STATUS(status);
            printf("Information on channel number %d:\n",i);
            /* print the dev info */
            printf("        Flags=0x%x\n",devList.Flags);
            printf("        Type=0x%x\n",devList.Type);
            printf("        ID=0x%x\n",devList.ID);
            printf("        LocId=0x%x\n",devList.LocId);
            printf("        SerialNumber=%s\n",devList.SerialNumber);
            printf("        Description=%s\n",devList.Description);
            printf("        ftHandle=0x%x\n",(unsigned int)devList.ftHandle);/*is 0 unless open*/
        }

        /* Open the first available channel */
        status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
        APP_CHECK_STATUS(status);
        printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);
        status = SPI_InitChannel(ftHandle,&channelConf);
        APP_CHECK_STATUS(status);

#if USE_WRITEREAD   
        {
            uint8 k,l;
            uint8 inBuffer[100];
            uint8 outBuffer[]={0x81,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,30,31,32,33,34,35,36,37,38,39};
            uint32 sizeToTransfer,sizeTransferred;
            for(k=0; k<5; k++)
            {
                printf("LoopCount = %u ",(unsigned)k);
                sizeToTransfer=10;
                sizeTransferred=0;
#if 1 // BYTES
                status = SPI_ReadWrite(ftHandle, inBuffer, outBuffer+k, sizeToTransfer, &sizeTransferred,
                    SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
                    SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
                    SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
#else // BITES
                status = SPI_ReadWrite(ftHandle, inBuffer, outBuffer+k, sizeToTransfer*8, &sizeTransferred,
                    SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
                    SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
                    SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
#endif
                APP_CHECK_STATUS(status);
                printf("status=0x%x sizeTransferred=%u\n", status, sizeTransferred);
                for(l=0;l<sizeToTransfer;l++)
                    printf("0x%x\n",(unsigned)inBuffer[l]);
                printf("\n");
            }
        }       
#else // USE_WRITEREAD
        for(address=START_ADDRESS_EEPROM;address<END_ADDRESS_EEPROM;address++)
        {
            printf("writing address = %02d data = %d\n",address,address+DATA_OFFSET);
            write_byte(SPI_SLAVE_0, address,(uint16)address+DATA_OFFSET);
        }

        for(address=START_ADDRESS_EEPROM;address<END_ADDRESS_EEPROM;address++)
        {
            read_byte(SPI_SLAVE_0, address,&data);
            printf("reading address = %02d data = %d\n",address,data);
        }
#endif // USE_WRITEREAD

        status = SPI_CloseChannel(ftHandle);
    }

#ifdef _MSC_VER
    Cleanup_libMPSSE();
#endif

#ifndef __linux__
    system("pause");
#endif
    return 0;
}

3 个答案:

答案 0 :(得分:1)

FT2232H / win7Pro也有同样的问题。

根本原因是libMPSSE获得了错误的locID并判断该设备不可用,因为D2XX始终将locId = 0返回给libMPSSE。

ftdi_mid.c

    case FT_DEVICE_2232H:
        if(((devList.LocId & 0xf)==1)|| ((devList.LocId & 0xf)==2))
        {
            isMPSSEAvailable =  MID_MPSSE_AVAILABLE;
        }
        break;

我修改条件并用mingw64重新编译libMPSSE。就是这样。

答案 1 :(得分:0)

我已就此问题写信给FTDI Chip。支持人员发送了一个有效的更新库。库的版本是0.6(测试版)。

答案 2 :(得分:0)

我在Ubuntu 19.10上有类似的问题。造成这种情况的根本原因是内核模块在连接FTDI之后便与FTDI进行交互,从而阻止了我与之建立连接。

解决方案是卸载该内核模块:

sudo rmmod ftdi_sio

libftd2xx ReadMe文件中也提到了它:

If the message "FT_Open failed" appears:
Perhaps the kernel automatically loaded another driver for the 
FTDI USB device.

sudo lsmod

If "ftdi_sio" is listed:
    Unload it (and its helper module, usbserial), as follows.

    sudo rmmod ftdi_sio
    sudo rmmod usbserial

Otherwise, it's possible that libftd2xx does not recognise your 
device's Vendor and Product Identifiers.  Call FT_SetVIDPID before
calling FT_Open/FT_OpenEx/FT_ListDevices.