[FX3] Bidirectional Auto DMA Channel with Manual Out Channel

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

cross mob
dmickels
Level 1
Level 1
10 sign-ins 5 replies posted 5 sign-ins

I have the FX3's hooked up back to back, with a host on each side like described in the Designing a Master Interface AN87216 example. I am using a GPIF State Machine that I found here on the forums that works for two bidirectional DMA Auto channels and I am trying to get it to work by making one of them allow for a Manual Out channel so that I can write custom data to it from the CPU to PPORT. Currently, whenever I call my function CyFxManualEPTransfer(), it gets stuck at state 11, RD_WR_IDLE_1 and fails to CommitBuffer with error code 66, CY_U3P_ERROR_INVALID_ADDR.

GPIF II State Machine:

stateMachine.PNG

CyFxManualEPTransfer Function:

 

CyU3PReturnStatus_t
CyFxManualEPTransfer (
        uint16_t  byteCount,
        uint8_t  *buffer)
{
    CyU3PDmaBuffer_t buf_p;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (byteCount == 0)
    {
        return CY_U3P_SUCCESS;
    }

    CyU3PDebugPrint (2, "\r[INFO] MANUAL EP access - size: 0x%x\r\n", byteCount);

    /* Update the buffer address and status. */
    buf_p.buffer = buffer;
    buf_p.status = 0;

    buf_p.size = glI2cPageSize;
    buf_p.count = glI2cPageSize;

    status = CyU3PDmaChannelSetupSendBuffer (&glChHandleInterruptLpUtoP, &buf_p);
    //status = CyU3PDmaChannelGetBuffer (&glChHandleInterruptLpUtoP, &buf_p, CYU3P_NO_WAIT);
    if (status != CY_U3P_SUCCESS)
    {
    	CyU3PDebugPrint (2, "\r[INFO] MANUAL EP: CyU3PDmaChannelSetupSendBuffer failed, Error code = %d\n", status);
    	//CyFxAppErrorHandler(status);
    	return status;
    }

    CyU3PDmaChannelSetWrapUp(&glChHandleInterruptLpUtoP);

    status = CyU3PDmaChannelCommitBuffer (&glChHandleInterruptLpUtoP, buf_p.size, 0);
    if (status != CY_U3P_SUCCESS)
    {
    	CyU3PDebugPrint (2, "\r[DEBUG] MANUAL EP: CyU3PDmaChannelCommitBuffer failed, Error code = %d\n", status);

    	uint8_t current_state;
		CyU3PDebugPrint (4, "\r[DEBUG] Write failed with error code %d\n\r", status );
		status = CyU3PGpifGetSMState(&current_state);
		CyU3PDebugPrint (4, "\r[DEBUG] Current state %d and err = %d\n\r", current_state, status );

    	//CyFxAppErrorHandler(status);
    	return status;
    }
    status = CyU3PDmaChannelWaitForCompletion(&glChHandleInterruptLpUtoP,
            CY_FX_FLASH_PROG_TIMEOUT);
    if (status != CY_U3P_SUCCESS)
    {
    	CyU3PDebugPrint (2, "MANUAL EP: CyU3PDmaChannelWaitForCompletion failed, Error code = %d\n", status);
    	//CyFxAppErrorHandler(status);
    	return status;
    }

    /* Need a delay between write operations. */
    CyU3PThreadSleep (10);

    return CY_U3P_SUCCESS;
}

 

DMA Channel setup for the Auto Channels:

 

 

    /* Create a DMA Auto Channel between four sockets of the U port.
     * DMA size is set based on the USB speed. */
    dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET;
    dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET;
    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
    dmaCfg.notification = 0;
    dmaCfg.cb = NULL;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;

    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleBulkLpUtoP,
            CY_U3P_DMA_TYPE_AUTO_SIGNAL, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Create a DMA Auto Channel between four sockets of the P port.
     * DMA size is set based on the USB speed. */
    dmaCfg.prodSckId = CY_FX_PRODUCER_PPORT_SOCKET;
    dmaCfg.consSckId = CY_FX_CONSUMER_USB_SOCKET;
    dmaCfg.notification = 0;
    dmaCfg.cb = NULL;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;
    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleBulkLpPtoU,
    CY_U3P_DMA_TYPE_AUTO_SIGNAL, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
         CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
         CyFxAppErrorHandler(apiRetStatus);
    }

 

 

 

DMA Channel setup for the Manual Out:

 

 

/* Now create the DMA channels required for read and write. */
    CyU3PMemSet ((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
    dmaConfig.size           = pageLen;
    /* No buffers need to be allocated as this will be used
     * only in override mode. */
    dmaConfig.count          = 0;
    dmaConfig.prodAvailCount = 0;
    dmaConfig.dmaMode        = CY_U3P_DMA_MODE_BYTE;
    dmaConfig.prodHeader     = 0;
    dmaConfig.prodFooter     = 0;
    dmaConfig.consHeader     = 0;
    dmaConfig.notification   = 0;
    dmaConfig.cb             = NULL;

    /* Create a channel to write to the EEPROM. */
    dmaConfig.prodSckId = CY_U3P_CPU_SOCKET_PROD;
    dmaConfig.consSckId = CY_FX_INTERRUPT_CONSUMER_PPORT_SOCKET;
    status = CyU3PDmaChannelCreate (&glChHandleInterruptLpUtoP,
            CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);
    if (status != CY_U3P_SUCCESS)
    {
    	WARNPRINT("MANUAL EP: CyU3PDmaChannelCreate OUT failed");
        return status;
    }

    /* Create a channel to read from the EEPROM. */
    dmaConfig.count          = 16;
    dmaConfig.prodSckId = CY_FX_INTERRUPT_PRODUCER_PPORT_SOCKET;
    dmaConfig.consSckId = CY_FX_INTERRUPT_USB_SOCKET;
    status = CyU3PDmaChannelCreate (&glChHandleInterruptLpPtoU,
    		CY_U3P_DMA_TYPE_AUTO, &dmaConfig);
    if (status != CY_U3P_SUCCESS)
    {
    	WARNPRINT("MANUAL EP: CyU3PDmaChannelCreate IN failed");
        return status;
    }

 

 

 

I have tried a variety of setups, but I can't seem to get it to work. Any suggestions?

0 Likes
1 Solution
Meghavi
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 10 likes received

Hi,

The transition should be from RD_WR_IDLE_1 to WR_FLAG_1 not DR_ADDR_1 as FLAG_D is asserted and data is being sent from the CPU, over GPIF II. Can you please check that once? Also, probe the flag and address lines of the GPIF II interface while sending the data.

Regards

View solution in original post

0 Likes
5 Replies
Meghavi
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 10 likes received

Hi,

 

1) Can you please share the whole state machine diagram?

2) What exactly are you planning to develop using this state machine?

3) Can you also let us know which API is returning CY_U3P_ERROR_INVALID_ADDR error and what exactly is error code 66?

 

Regards,

Meghavi

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

I've attached the project files, including the GPIF state machines. The picture above is from master.cydsn.

I am developing this to serve as an interface to allow communication between the hosts attached to each FX3. The idea is that if host A needs to communicate with host B, host A can send a vendor request which will send a message over GPIF and into the interrupt in endpoint for host B to read and react accordingly. 

CyU3PDmaChannelCommitBuffer is returning CY_U3P_ERROR_INVALID_ADDR when called which is error code 66 from the cyu3error.h includes. I'm not sure why this error is occurring.

 

 

[DEBUG] MANUAL EP: CyU3PDmaChannelCommitBuffer failed, Error code = 66
[DEBUG] Write failed with error code 66   
[DEBUG] Current state 11 and err = 0

 

 

EDIT:
I was able to get the Manual Transfer working to an endpoint on the same FX3, but am struggling to get it to work over GPIF. There is no longer any errors from the DMA related to failed commits, or the state machine not working, and everything appears to send successfully. However, I am not able to read it in on FX3 B that is attached via GPIF. Currently, if I replace the dmaCfg.consSckId in the DMA setup below to a UIB socket instead of a PPORT socket, I am able to read in the data from the interrupt endpoint, so I know that the data is being commit properly.

I am using a Manual OUT channel to send to the PPORT (socket 3):

 

    /* Create a DMA MANUAL_OUT channel for the consumer socket. */
    dmaCfg.notification = CY_U3P_DMA_CB_CONS_EVENT | CY_U3P_DMA_CB_PROD_EVENT;
    dmaCfg.cb = GpifToUsbDmaCallback;
    dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD;
    dmaCfg.consSckId = CY_FX_INTERRUPT_CONSUMER_PPORT_SOCKET;
    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleInterruptLpUtoP,
            CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

 

and have an Auto Channel setup to read on the other side. (I do intend to have this work from both FX3's, so FX3A can send to FX3B interrupt endpoint, and FX3B can also send to FX3A interrupt endpoint.)

 

    dmaCfg.prodSckId = CY_FX_INTERRUPT_PRODUCER_PPORT_SOCKET;
    dmaCfg.consSckId = CY_FX_INTERRUPT_USB_SOCKET;
    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
    /* No callback is required. */
    dmaCfg.notification = 0;
    dmaCfg.cb = NULL;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;

    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleInterruptLpPtoU,
    		CY_U3P_DMA_TYPE_AUTO, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

 

I have tried to make this a Manual channel as well to see if that was the issue, but didn't have any luck with that.

I have tried referencing the solution here: FX3 CPU to Parallel Port Socket DMA Operation-Manual Out/In as it seems to be the same issue that I am having, but can't seem to find why I am not able to read the data from the interrupt in endpoint on the attached FX3. 

I have updated the included FX3 files to my current progress.

0 Likes
Meghavi
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 10 likes received

Hi,

  1. FX3A is Scopeside project, FX3B is PC side project. So, FX3 A is sending the data to FX3B over the GPIF II thread 3. Is this correct understanding? 
  2. The Commitbuffer inside the function CyFxManualEPTransfer() is no longer failing. Also, from the line "there is no longer any errors from the DMA related to failed commits, or the state machine not working, and everything appears to send successfully.", we understand that state machine is working properly. How was this confirmed. Can you share the UART debug logs?
  3. Also, probe the pins of the GPIF II interface while sending the data from FX3A to FX3B for us to check.

Regards

0 Likes

Hi,


  1. FX3A is Scopeside project, FX3B is PC side project. So, FX3 A is sending the data to FX3B over the GPIF II thread 3. Is this correct understanding? 

That is correct. I would like to us a Manual Out DMA to transfer from the CPU, over GPIF II, and be received on the other end and pushed to the interrupt endpoint.

After further investigating, it looks like there is no actual data being transmitted over the GPIF II interface during the manual writes after probing the pins with a logic analyzer. I had initially assumed that it must be sending as I was no longer getting the errors I had previously been getting, but this was a wrong assumption.

From my current debug log, I started checking which states it was in during the manual write, at it appears to be just stuck at the 10 (DR_ADDR_1) and 11 (RD_WR_IDLE_1) and never actual moves on to the next stages.

 

 

[INFO] VENDOR REQ: 199, wValue: 0, wIndex: 0
[DEBUG] CUSTOM TRIGGER                      ▒▒
[INFO] MANUAL EP access - size: 0x4
[DEBUG] Starting State: 11 and err = 0
[DEBUG] State after Get Buffer: 10 and err = 0
[DEBUG] State after Commit: 11 and err = 0    ▒▒,
[INFO] VENDOR REQ: 199, wValue: 0, wIndex: 0.
[DEBUG] CUSTOM TRIGGER                      ▒▒
[INFO] MANUAL EP access - size: 0x4
[DEBUG] Starting State: 10 and err = 0
[DEBUG] State after Get Buffer: 11 and err = 0
[DEBUG] State after Commit: 11 and err = 0    ▒▒,
[INFO] VENDOR REQ: 199, wValue: 0, wIndex: 0.
[DEBUG] CUSTOM TRIGGER                      ▒▒
[INFO] MANUAL EP access - size: 0x4
[DEBUG] Starting State: 11 and err = 0
[DEBUG] State after Get Buffer: 10 and err = 0
[DEBUG] State after Commit: 10 and err = 0    ▒▒,

 

 

(Code showing where exactly these messages come from below)

However, when adjusting the transition from RD_WR_IDLE_1 to DR_ADDR_1 to be just FLAG_C, I am able to realize that FLAG_C is being set, but DMA_RDY_TH2 is never set.

Capture.PNG

Specifically, it looks like FLAG_C is triggering, but not DMA_RDY_TH2. Is there a reason that the DMA_RDY_TH* flag wouldn't be set, other then of course the DMA not being ready?

And if it is the DMA not being ready, what commands or changes am I missing in the write step? I am able to make the following segment of code work if I am writing to UIB, but not PPORT.

 

 

 

//DMA Setup for glChHandleInterruptLpUtoP
    /* Create a DMA MANUAL_OUT channel for the consumer socket. */
    dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD;
    dmaCfg.consSckId = CY_FX_INTERRUPT_CONSUMER_PPORT_SOCKET;
    dmaCfg.notification = 0;
    dmaCfg.cb = NULL;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;
    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleInterruptLpUtoP,
            CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        DBGPRINT ("CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

//Function called to init a transfer on glChHandleInterruptLpUtoP from CPU to PPORT.
CyU3PReturnStatus_t
CyFxManualEPTransfer (
        uint16_t  byteCount,
        uint8_t  *buffer)
{
    CyU3PDmaBuffer_t buf_p;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
	uint8_t current_state;

    if (byteCount == 0)
    {
        return CY_U3P_SUCCESS;
    }

    INFOPRINT ("MANUAL EP access - size: 0x%x", byteCount);

	status = CyU3PGpifGetSMState(&current_state);
	DBGPRINT ("Starting State: %d and err = %d", current_state, status );

    /* Update the buffer address and status. */

    status = CyU3PDmaChannelGetBuffer (&glChHandleInterruptLpUtoP, &buf_p, CYU3P_WAIT_FOREVER);
    if (status != CY_U3P_SUCCESS)
    {
    	INFOPRINT ("MANUAL EP: CyU3PDmaChannelSetupSendBuffer failed, Error code = %d", status);

		DBGPRINT ("Write failed with error code %d", status );
		status = CyU3PGpifGetSMState(&current_state);
		DBGPRINT ("Current state %d and err = %d", current_state, status );

    	//CyFxAppErrorHandler(status);
    	return status;
    }

	status = CyU3PGpifGetSMState(&current_state);
	DBGPRINT ("State after Get Buffer: %d and err = %d", current_state, status );

    int i;
    for(i = 0; i < byteCount; i++){
    	CyU3PMemSet(&buf_p.buffer[i], buffer[i], 1);
    }

    status = CyU3PDmaChannelCommitBuffer (&glChHandleInterruptLpUtoP, buf_p.size, 0);
    if (status != CY_U3P_SUCCESS)
    {
    	DBGPRINT ("MANUAL EP: CyU3PDmaChannelCommitBuffer failed, Error code = %d", status);

		DBGPRINT ("Write failed with error code %d", status );
		status = CyU3PGpifGetSMState(&current_state);
		DBGPRINT ("Current state %d and err = %d", current_state, status );

    	//CyFxAppErrorHandler(status);
    	return status;
    }

	status = CyU3PGpifGetSMState(&current_state);
	DBGPRINT ("State after Commit: %d and err = %d", current_state, status );

    return CY_U3P_SUCCESS;
}

 

 

EDIT:
I changed all the transitions in the state diagram to be just FLAC_C, and I am able to pick up an empty buffer being sent from the other FX3. So it really is just the DMA_RDY_TH2 flag not being set.

 

0 Likes
Meghavi
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 10 likes received

Hi,

The transition should be from RD_WR_IDLE_1 to WR_FLAG_1 not DR_ADDR_1 as FLAG_D is asserted and data is being sent from the CPU, over GPIF II. Can you please check that once? Also, probe the flag and address lines of the GPIF II interface while sending the data.

Regards

0 Likes