USB3.0 FX3 Programming issues with SDK 321 BETA

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hello,

   

I try to get the I2C interface working correct with DMA. So far so good the point is, I can send and receive each one time with the function "CyU3PI2cSendCommand". The Callback with the event "CY_U3P_I2C_EVENT_RX_DONE" and "CY_U3P_I2C_EVENT_TX_DONE" occurs in each case too. I think it needs anything to be done at this time but I do not know what! I tried some DMA functions:

   

- CyU3PDmaChannelAbort

   

- CyU3PDmaChannelResume

   

- CyU3PDmaChannelReset

   

The second send or receive does each time nothing. The I2cSendCommand call return SUCCESS but nothing happened.

   

 

   

How can I use the I2C module more than one time in DMA mode?

   

 

   

 C - Code:

   

 

   

CyU3PErrorCode_t IS_I2cInit(void)
{
    CyU3PErrorCode_t status = CY_U3P_SUCCESS;
    CyU3PI2cConfig_t config;

    status = CyU3PI2cInit();

    if(status != CY_U3P_SUCCESS)
    {
        return status;
    }

    status = IS_I2cCreateDmaChannel();
    if(status != CY_U3P_SUCCESS)
    {
        return status;
    }

    glWriteBuffer.buffer = &glWriteData[0];
    glWriteBuffer.count  = 0;
    glWriteBuffer.size   = I2C_DMA_BUF_SIZE;
    glWriteBuffer.status = NULL;

    glReadBuffer.buffer  = &glReadData[0];
    glReadBuffer.count   = 0;
    glReadBuffer.size    = I2C_DMA_BUF_SIZE;
    glReadBuffer.status  = NULL;

    glI2cLock = CyFalse;


    config.bitRate = 400000; // 400 kHz
    config.isDma = CyTrue;  // Register transfer mode
    config.busTimeout = 0xFFFFFFFFU; // no timeout
    config.dmaTimeout = 0xFFFF; // no timeout

    status = CyU3PI2cSetConfig(&config, &IS_I2cIR);

    if(status != CY_U3P_SUCCESS)
    {
        return status;
    }

    return status;
}
 

   

void IS_I2cIR(CyU3PI2cEvt_t evt, CyU3PI2cError_t error)
{
    CyU3PErrorCode_t status = CY_U3P_SUCCESS;
    switch(evt)
    {
    case CY_U3P_I2C_EVENT_RX_DONE:
        if(glI2cLock == CyTrue)
        {
            status = CyU3PDmaChannelAbort(&glDmaChannelHandleI2c);
            glI2cLock = CyFalse;
        }
        else
        {
            IS_I2cErrorEvent(error);
        }
        break;
    case CY_U3P_I2C_EVENT_TX_DONE:
        if(glI2cLock == CyTrue)
        {
            status = CyU3PDmaChannelAbort(&glDmaChannelHandleI2c);
            glI2cLock = CyFalse;
        }
        else
        {
            IS_I2cErrorEvent(error);
        }
        break;
    case CY_U3P_I2C_EVENT_TIMEOUT:
        break;
    case CY_U3P_I2C_EVENT_LOST_ARBITRATION:
        break;
    case CY_U3P_I2C_EVENT_ERROR:
        IS_I2cErrorEvent(error);
        break;
    default:
        break;
    }
}

   

 

   

CyU3PErrorCode_t IS_I2cWrite(uint8_t dvcAdr, uint8_t sizeAdr, uint8_t *pAdr, uint8_t sizeData, uint8_t *pData)
{
    while(glI2cLock==CyTrue);

    CyU3PErrorCode_t status = CY_U3P_SUCCESS;

    glWriteBuffer.buffer = pData;
    glWriteBuffer.count = sizeData;

    status = CyU3PDmaChannelSetupSendBuffer(&glDmaChannelHandleI2c, &glWriteBuffer);
    //if(status == CY_U3P_SUCCESS)
    {
        glI2cLock = CyTrue;
        status = IS_I2cCommunicate(CyFalse, dvcAdr, sizeAdr, pAdr, sizeData, pData);
    }
    return status;
}
CyU3PErrorCode_t IS_I2cRead(uint8_t dvcAdr, uint8_t sizeAdr, uint8_t *pAdr, uint8_t sizeData, uint8_t *pData)
{
    while(glI2cLock==CyTrue);

    CyU3PErrorCode_t status = CY_U3P_SUCCESS;

    glReadBuffer.buffer = pData;
    glReadBuffer.count = sizeData;

    status = CyU3PDmaChannelSetupRecvBuffer(&glDmaChannelHandleI2c, &glReadBuffer);
    //if(status == CY_U3P_SUCCESS)
    {
        glI2cLock = CyTrue;
        status = IS_I2cCommunicate(CyTrue, dvcAdr, sizeAdr, pAdr, sizeData, pData);
    }
    return status;
}
CyU3PErrorCode_t IS_I2cCommunicate(CyBool_t read, uint8_t dvcAdr, uint8_t sizeAdr, uint8_t *pAdr, uint8_t sizeData, uint8_t *pData)
{
    CyU3PErrorCode_t status = CY_U3P_SUCCESS;
    CyU3PI2cPreamble_t preamble;
    uint8_t CntBytesPreamble = 0;
    uint8_t LengthAdr = 0;
    uint8_t dvcAdrWrite = dvcAdr & 0xFE;
    uint8_t dvcAdrRead = dvcAdr | 0x01;

    preamble.ctrlMask = 0;
    preamble.length = 0;

    if(sizeAdr > 0)
    {
        preamble.buffer[0] = dvcAdrWrite;
        CntBytesPreamble++;
    }

    for(LengthAdr = 0; LengthAdr < sizeAdr; LengthAdr++)
    {
        preamble.buffer[LengthAdr+1] = pAdr[LengthAdr];
        CntBytesPreamble++;
    }

    if(read == CyTrue)
    {
        if(sizeAdr > 0)
        {
            preamble.buffer[++LengthAdr] = dvcAdrRead;
            preamble.length = (++CntBytesPreamble);
            preamble.ctrlMask = 0x01 << (CntBytesPreamble-2);
        }
    }
    else
    {
        preamble.length = CntBytesPreamble;
        preamble.ctrlMask = 0x00;
    }

    //status = CyU3PI2cSetBlockXfer(sizeData);
    status = CyU3PI2cSendCommand(&preamble, sizeData, read);

    return status;
}

CyU3PErrorCode_t IS_I2cCreateDmaChannel(void)
{
    CyU3PDmaChannelConfig_t dmaI2cConfig;
    CyU3PErrorCode_t status = CY_U3P_SUCCESS;


    /* Create a DMA MANUAL Channel between two sockets of the U port */
    dmaI2cConfig.size = I2C_DMA_BUF_SIZE;
    dmaI2cConfig.count = I2C_DMA_BUF_COUNT;
    dmaI2cConfig.prodSckId = CY_U3P_LPP_SOCKET_I2C_PROD;
    dmaI2cConfig.consSckId = CY_U3P_LPP_SOCKET_I2C_CONS;
    dmaI2cConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
    dmaI2cConfig.notification = CY_U3P_DMA_CB_XFER_CPLT;
    dmaI2cConfig.cb = Is_I2cDmaCallback;
    dmaI2cConfig.prodHeader = 0;
    dmaI2cConfig.prodFooter = 0;
    dmaI2cConfig.consHeader = 0;
    dmaI2cConfig.prodAvailCount = 0;

    /* Create the channel */
    status = CyU3PDmaChannelCreate(&glDmaChannelHandleI2c, CY_U3P_DMA_TYPE_AUTO, &dmaI2cConfig);
    return status;
}

 

0 Likes
9 Replies
Anonymous
Not applicable

Sorry I forgot something....

   

The functions

   

- CyU3PDmaChannelAbort

   

- CyU3PDmaChannelResume

   

- CyU3PDmaChannelReset

   

returns with "CY_U3P_ERROR_MUTEX_FAILURE"

0 Likes
lock attach
Attachments are accessible only for community members.
KarthikS_81
Employee
Employee
Welcome! 5 replies posted First solution authored

CyU3PDmaChannelReset is the correct API call to be used to clear the DMA channel between operations. The difference is that you need to ensure that the DMA channel is back to idle state before you reset it.

   

I am attaching your code with the changes required to make this work correctly. I am also summarizing the changes below:

   

1. Changed the list of DMA notifications (in the parameter to CyU3PDmaChannelCreate) to include CY_U3P_DMA_CB_SEND_CPLT and CY_U3P_DMA_CB_RECV_CPLT. The CY_U3P_DMA_CB_XFER_CPLT will not work when you are using the CyU3PDmaChannelSetupSend/RecvBuffer API calls.

   

2. Added a new flag to track the status of the DMA channel. This flag is being made true after the CyU3PDmaChannelSetupSendBuffer or RecvBuffer is called, and made false when the DMA callback is received. I have also added a sample implementation of the DMA callback because the original code did not include this.

   

3. In the I2C callback (IS_I2cIR), wait for the DMA callback to come and then call CyU3PDmaChannelReset to clear up the channel.

   

4. Enabled the return status checks for the CyU3PDmaChannelSetupSend/RecvBuffer API calls. If these API calls fail, the I2C callback will not be called as the transfer will not get complete. Therefore, it is necessary to check the status here.

   

5. Changed all CyU3PErrorCode_t variables to CyU3PReturnStatus_t variables. This is the correct type to be used for FX3 API return codes.

   

6. Added some sample test code that calls the read/write functions repeatedly. Please note that a delay (of about 10 ms) is required between any I2C write operation and the next I2C read/write operation when using the current version of the drivers. This restriction is noted in our release notes as well.

   

I have marked all places where I changed your code with comments including the word "FIX". This code was tested with an I2C EEPROM device and is working fine.

   

Regards,

   

Karthik S

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi kys,

   

//

   

many thanks for your answer. I tried to implement your fixes into my code but actually can not get it to work.

   

//

   

//

   

I get just one DMA Callback after the first write or read. If I write or read next time I did not get the DMA Callback again so the DMA-Busy Flag gets never be reseted and it stays forever in the endless loop.

   

//

   

I attached my example.

0 Likes
KarthikS_81
Employee
Employee
Welcome! 5 replies posted First solution authored

Hi Lumpi6,

   

Your code looks fine and a similar application is working correctly on my test setup.

   

I will look into this and get back with debug suggestions within a day.

   

Thanks and regards,

   

Karthik

0 Likes
KarthikS_81
Employee
Employee
Welcome! 5 replies posted First solution authored

Hi Lumpi6,

   

I have a couple of questions on your application.

   

1. What is the priority level you have assigned to the thread from which you are making the I2cDmaWrite and I2cDmaRead calls?

   

2. Are you getting error returns from any of the API calls that you are making as of now (DmaChannelReset, DmaChannelSetupSendBuffer, DmaChannelSetupRecvBuffer or I2cSendCommand)?

   

3. If possible, please provide a pointer to the I2C device that you are trying to access via the FX3.

   

Thanks,

   

Karthik

0 Likes
Anonymous
Not applicable

Hi Karthik,

   

|

   

1. Thread - Creation

   

    /* Create the thread for the application */
    retThrdCreate = CyU3PThreadCreate (&I2cAppThread,           /* I2C in DMA Thread structure */
                          "I2C in DMA Mode TEST",               /* Thread ID and Thread name */
                          I2cAppThread_Entry,                   /* I2C in DMA Thread Entry function */
                          0,                                    /* No input parameter to thread */
                          ptr,                                  /* Pointer to the allocated thread stack */
                          THREAD_I2C_THREAD_STACK,              /* I2C in DMA Thread stack size */
                          THREAD_I2C_THREAD_PRIORITY,           /* I2C in DMA Thread priority */
                          THREAD_I2C_THREAD_PRIORITY,           /* I2C in DMA Thread priority */
                          CYU3P_NO_TIME_SLICE,                  /* No time slice for the application thread */
                          CYU3P_AUTO_START                      /* Start the Thread immediately */
                          );

#define THREAD_I2C_THREAD_STACK       (0x1000)                  /* I2C in DMA thread stack size */
#define THREAD_I2C_THREAD_PRIORITY    (8)                       /* I2C in DMA thread priority */
|

   

2. I get no Errors of any API calls.

   

|

   

3. The I2C EEPROM is a M24C64 and this is working fine with the standard send and receive functions of the I2C.

   

|

   

Best regards

   

lumpi6

0 Likes
Anonymous
Not applicable

Hi Karthik,

   

I can write two times, four times so that I think the write mechnism works fine. The problem is that I can just read once and then the DMA-Busy flag will never be set to zero.

   

The send notification "CY_U3P_DMA_CB_SEND_CPLT" happens each time at the DMA callback but the receive notification "CY_U3P_DMA_CB_RECV_CPLT" or any other call never happens. Why? I think there is the problem...

   

Best regards

   

lumpi6

0 Likes
KarthikS_81
Employee
Employee
Welcome! 5 replies posted First solution authored

Hi Lumpi6,

   

Thanks for providing the data.

   

You are seeing this problem because the read data (2 bytes in your case) is not filling the DMA buffer (64 bytes in your case). In such a case, the DMA channel is on hold waiting for more data to come in and fill the buffer.

   

The DMA buffer size is specified through the g_DmaBufferRead.size parameter and needs to be a multiple of 16 bytes.

   

We will work on updating the API to take care of this case by the time of the next release.

   

For now, please use one of the following work-arounds:

   

1. Use the CyU3PI2cReceiveBytes API instead of a DMA operation when you want to read small amounts of data. You can use the DMA read operation as you are currently doing when you want to read data that will fill the entire DMA buffer.

   

2. Use the "CyU3PDmaChannelSetWrapUp (&g_HandleI2cDmaCh)" from the I2cDmaIR function on receipt of a CY_U3P_I2C_EVENT_RX_DONE event. This will cause the DMA buffer to be committed and result in receipt of the DMA callback.

   

Please let me know if you have problems/concerns with these work-arounds.

   

With regards,

   

Karthik

0 Likes
Anonymous
Not applicable

 Hi guys,

   

I'm trying to use I2C in DMA mode as Lumpi6 wanted. So, I would like to know has this been supported in newest version of FX3 SDK?

   

Thanks!

   

Teo

0 Likes