USB_FS with Auto-DMA / API handling: HowTo?

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

cross mob
RaAl_264636
Level 6
Level 6
50 sign-ins 25 sign-ins 10 solutions authored

Hi,

is there anything special to do when using USB_FS component with auto-DMA mode? I've seen some threads mentioning that the EPx_ISR entry/exit callbacks are needed because they inform about a finished DMA transfer. But I couldn't find any example code about it. The only thing is AN56377, which uses an ISOC IN endpoint, but it seems that there isn't anything special with the ISRs and/or callbacks. My code is based on USB_FS component datasheet and the example #1 of AN56377, modified for DMA auto mode.

Currently I'm using an IN/OUT endpoint pair, where the packet received from the OUT endpoint should be looped back by the IN endpoint:

//global buffers

uint8 Interrupt_IN_Buffer[64], EP1_Count;

uint8 Interrupt_OUT_Buffer[64], EP2_Count;

uint8 App_Interrupt_OUT_Buffer[64];

//init USB DMA buffers (called in main() function)

USBFS_LoadInEP(EP1, Interrupt_IN_Buffer, 64);

USBFS_ReadOutEP(EP2, Interrupt_OUT_Buffer, 64);

//USB endpoint handling, should simply loop back

if(USBFS_GetEPState(EP2) == USBFS_OUT_BUFFER_FULL) {

    /* Determine the number of bytes received */

    EP2_Count = USBFS_GetEPCount(EP2);

    memcpy(&App_Interrupt_OUT_Buffer, &Interrupt_OUT_Buffer, EP2_Count);    //uses application buffer as intermediate memory

    /* Create loopback by reloading data received into IN endpoint */

    while(USBFS_IN_BUFFER_EMPTY != USBFS_GetEPState(EP1));

    memcpy(&Interrupt_IN_Buffer, &App_Interrupt_OUT_Buffer, EP2_Count);    //uses application buffer as intermediate memory

    USBFS_LoadInEP(EP1, NULL, EP2_Count);

    /* Re-arm the Out Endpoint */

    USBFS_EnableOutEP(EP2);

}

What am I missing?

Regards

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

Hi Ralf,

Please find the attached project for reference.

Please check this on Control center:

1.First chose out EP (0x02) and fill "Text to send" field with 64 bytes and then send "Transfer Data-Out"

2.Then chose IN ISOC (0x81) and chose "Byte to transfer" with 64 bytes and click "Transfer Data-In"

It does loopback of received data on Out EP to In EP for ISOC Transfers

View solution in original post

0 Likes
21 Replies
AnkitaS_51
Employee
Employee
100 likes received 50 likes received 25 likes received

Hi,

Where have you seen that EPx_ISR entry/exit callbacks are needed because they inform about a finished DMA transfer?

There are ISRs for each endpoints inside the file USBFS_episr.c. For eg: You can add your code in the OUT EP. When host is sending data to device OUT EP ISR will be triggered.

Please refer to this doc  :

http://www.cypress.com/file/105231/download

Presently, the code is not publicly available associated with the above mentioned document.

In the doc following is mentioned which will be helpful for you:

If certain data suppose 64 bytes is sent to the PSoC 3 / PSoC 5 (that is, the Out endpoint (suppose it is EP2) in PSoC 3 / PSoC 5 receives this data). This operation triggers out endpoint interrupt inside the PSoC 3 / PSoC 5 device. This interrupt routes the program to CY_ISR(USBFS_EP_2_lSR) inside the USBFS_episr.c file.

In the ISR:

1. A flag to indicate the occurrence of interrupt is set (USB_interruptFlag)

2. In the main code, when this flag is set, a  function  can be called

3. The function will do the following:

a. Reads how many bytes have been sent to the Out endpoint

b. Reads the bytes sent to the Out endpoint and stores to a local buffer

c. Increments the received data

d. Puts the incremented data to the In endpoint buffer so that when the Read button is clicked in the GUI, the data from the In endpoint buffer is sent to PC

Please refer to this doc which can give you an idea how to do loopback :

http://www.cypress.com/file/105231/download

0 Likes

Hi anks,

>>> Where have you seen that EPx_ISR entry/exit callbacks are needed because they inform about a finished DMA transfer?

Hima mentioned it here: USB DMA with Automatic Memory Management

But he didn't explain how it should be done.

Thank you for the document, I'll go through it. What I try to figure out is if it's needed to hook up to the ISRs when using DMA auto mode. None of the examples provided seems to use them (e.g. AN56377 uses DMA auto mode, but the ISRs are not touched).

When I debug my code above, it seems that the firmware is permanently handling DMA part of the USB API, which causes my application to hang. That's why I asked if anything must be done with the IRQs (e.g. clear DMA complete interrupt flags).

Regards

0 Likes

Hi,

Hima is correct in her explanation.

You can use EP's  ISR as needed in application.

As said by Hima "The ISR will get triggered only when data is loaded into SRAM, in case of OUT transfer."

DMA interrupt's are internal to USB component .Please go through USBFS datasheet for proper understanding.

User can edit EP ISR in callback areas in USBFS_episr as indicated as for eg:

"/* `#START EP1_USER_CODE` Place your code here */

/* `#END` */"

0 Likes

Hi anks,

Hima itself didn't mention DMA mode, that's true. But the topic starter asked about DMA auto mode, that's why I assumed it's needed for DMA. From your answers I understand that I don't need to use the callbacks.

So, the question is why my above code isn't working. It should be a simple loop back with DMA auto mode.

Regards

0 Likes

Hi,

I think you need to use callbacks that is what I mentioned in my previous interactions and the doc suggested the same.

By mistake, I given the same link both times in first interaction, please find this doc:

http://www.cypress.com/file/105261/download

So I suggest you to go through the documents previously suggested and the USBFS datasheet for choosing correct method.

0 Likes

Hi Ralf,

As far as for code snippet posted by you:

"USBFS_LoadInEP(EP1, Interrupt_IN_Buffer, 64);

USBFS_ReadOutEP(EP2, Interrupt_OUT_Buffer, 64);"

These API's should be used only after checking the particular EPs state.

They cannot be used as such directly without any check.

0 Likes

Hi anks,

those APIs are only used once with 2nd argument as buffer pointer in initialization (please see the code comments).

The main loop itself doesn't use ReadOutEP() after initialization - from my understanding of the USBFS API, this isn't needed when using DMA auto mode.

GetEPState() is used for both endpoints. For the IN endpoint, LoadInEP(EP1, NULL, EP2_Count) is used. After that, EnableOutEP(EP2) is called to get ready for next out packet.

Regards

0 Likes

Hi,

For using ReadOutEP API you should do something which as follows, for initialization part which is not part of main loop:

/* Get the active interface number and reinitalize DMA */

AltSettingNumber = USBFS_GetInterfaceSetting(0);

#define ALT_SETTING_ZERO_BANDWIDTH              0

if (AltSettingNumber != ALT_SETTING_ZERO_BANDWIDTH)          

        {

            /* Init DMA configurations for  OUT EP */

            USBFS_ReadOutEP(EP2, Interrupt_OUT_Buffer, 64);

            USBFS_EnableOutEP(EP2); 

}

0 Likes

Hi anks,

I'm doing all those things in my code. I'm sorry if my example code above isn't clear, so I try to clarify:

//init USB DMA buffers (called in main() function)

USBFS_LoadInEP(EP1, Interrupt_IN_Buffer, 64);

USBFS_ReadOutEP(EP2, Interrupt_OUT_Buffer, 64);

//USB endpoint handling, should simply loop back

if(USBFS_GetEPState(EP2) == USBFS_OUT_BUFFER_FULL) {

    /* Determine the number of bytes received */

    EP2_Count = USBFS_GetEPCount(EP2);

    memcpy(&App_Interrupt_OUT_Buffer, &Interrupt_OUT_Buffer, EP2_Count);    //uses application buffer as intermediate memory

    /* Create loopback by reloading data received into IN endpoint */

    while(USBFS_IN_BUFFER_EMPTY != USBFS_GetEPState(EP1));

    memcpy(&Interrupt_IN_Buffer, &App_Interrupt_OUT_Buffer, EP2_Count);    //uses application buffer as intermediate memory

    USBFS_LoadInEP(EP1, NULL, EP2_Count);

    /* Re-arm the Out Endpoint */

    USBFS_EnableOutEP(EP2);

}

The endpoint handling is based on AN56377 with modifications for DMA auto handling (as far as I understood the DMA auto handling). Is there anything else which must be done to get it to work?

Regards

0 Likes

Please share your main.c file.

You need to use EP ISRs Callbacks functions,   For more information regarding Macro callbacks, refer to the Macro Callbacks topic in the PSoC Creator Help.

0 Likes

Hello anks,

You need to use EP ISRs Callbacks functions,

now it seems that we're getting on the right way

As you mentioned in your answer you accidentally posted the same document link two times - my mistake is that I accidentally missed the link to the second document. Sorry for that. In combination with the first document, the picture gets more clear

From reading EP561332 (your 2nd document), what I understood is the following:

  • ISR callbacks have to be configured for the OUT endpoints, where the ISR:
    • fires when data has been received and DMA handling has finished (after the last DMA transaction for sizes greater than endpoint size)
    • copies the received data to a second buffer for later processing
    • sets a flag to indicate to the main application that data has been received
    • re-arms the corresponding OUT endpoint by calling USBFS_EnableOutEP()
  • ISR callbacks have to be configured for the IN endpoints, where the ISR:
    • fires when the data has been read by the host (after the last DMA transaction for sizes greater than endpoint size)
    • sets a flag indicating that the data has been retrieved from host and another IN transfer can be initiated or alternatively directly initiates another IN transfer if more than the packet size has to be sent
    • re-arms the corresponding IN endpoint by calling USBFS_LoadInEP()

So, remaining points are:

  1. Is the above workflow true? If yes, I'll try to implement it that way and give feedback if the issues are resolved.
  2. I checked USBFS component datasheet as well as AN56733, IMHO none of them clearly state that the user needs to implement custom ISR to handle the DMA transactions (USBFS component datasheet description gives the impression that all neccessary interrupt handling is done internally - additionally the only interrupt callback mentioned is for the OUT packet re-transmission chapter). With the two documents provided by you this gets a bit more clear. So I want to suggest that both USBFS component datasheet and AN56733 are reworked to make the user aware of that. Please take this into consideration.
  3. For IN endpoints, what's the maximum buffer size for USBFS_LoadInEP()? USBFS component datasheet states the following for DMA auto mode:
    1. Each endpoint buffer size is 32 bytes and the rest of the USB block buffer (size of 512 bytes) is a common area which acts as a FIFO for the endpoint that to which the host currently communicates.

    2. When the endpoint buffer is full, the data comes into the FIFO (common area). This allocation allows servicing endpoint sizes greater than the USB block buffer size, because the USB block buffer is used as the infrastructure to manage data transfers and the actual data is stored in the system SRAM memory.

    3. The above description states that the dedicated hardware block size is 512 bytes. But it's also mentioned that the endpoint size can be greater than 512 bytes. As far as I know this is only true for ISO endpoints and only applicable if only one endpoint is used. The above description sounds like the buffer sizes can be of any size. Which one is true? Please clarify what the maximum buffer sizes are depending on number of endpoints used and endpoint size.

Thanks for your help until now, very appreciated.

Regards

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

Hi anks,

I'm sorry, I don't get it to work I attached the current project, running on a CY8CKIT-059. There are some outputs to serial interface for debug output and speed measurement. The host application is a small C# software, which transmit random data to the interrupt OUT endpoint and receives the same data on IN endpoint. This works well if the USB component is configured for manual-static buffer management.

For DMA-auto buffer management, I made the following changes:

1) the endpoint interrupt callbacks are registered for all six endpoints (three pairs of INT/BULK/ISO IN/OUT endpoints, same as AN56377)

2) each interrupt only sets a endpoint variable to 1 for further processing in the main application

3) the original endpoint buffers are registered for DMA handling in initialization by calling USBFS_LoadInEP() and USBFS_ReadOutEP() with non-null pointer value

4) there is an additional application buffer for each OUT endpoint to store the data for later processing as suggested by the documents you provided (I know that this buffer is not needed for simple loop transfer, but in a real project this buffer is needed)

5) the AN56377 original functions which handle the data transfer have been modified to check both variables mentioned in #2. If both are set, the OUT endpoint data is retrieved and copied to the local buffer mentioned in #4. After that, the contents of this buffer are copied to the IN endpoint buffer and the IN endpoint is re-enabled by calling USBFS_LoadInEP() with null pointer and size of the retrieved data.

The above workflow is what I understand how to do it, but it doesn't work. Can you clarify what I'm still doing wrong?

Regards

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

Hi Ralf,

Please find the attached project for reference.

Please check this on Control center:

1.First chose out EP (0x02) and fill "Text to send" field with 64 bytes and then send "Transfer Data-Out"

2.Then chose IN ISOC (0x81) and chose "Byte to transfer" with 64 bytes and click "Transfer Data-In"

It does loopback of received data on Out EP to In EP for ISOC Transfers

0 Likes

Hi anks,

I adapted the scheme to the interrupt endpoints of example #1 of AN56377. I hooked up a callback for the USBFS_EP_DMA_DONE_ISR exit for debug purpose. It seems that after the first OUT transaction the ISR fires continously. Is this intended behaviour?

It slows down the application and the code couldn't work the USB_FS_LoadInEndpoint() function.

Regards

0 Likes

I think you are choosing DMA with Automatic Buffer Management in the project.

Please check the reference project attached in previous interaction which is using EP2 ISR.

USBFS_EP_DMA_DONE_ISR is  intended for internal Component use only.

0 Likes

Hi anks,

>>> I think you are choosing DMA with Automatic Buffer Management in the project.

Yes, that's what I stated in the first posting As a base I used AN56377 example #1, because I want to see the difference in speed for all endpoint types.

What I don't understand is why it's so hard to modify the example so that it works with auto-DMA mode. According to the documentation and your help, it should run. I'm still investigating. I'll remove the USBFS_EP_DMA_DONE_ISR callback.

Regards

0 Likes

Hi anks,

I'm getting first results based on your last example provided. Many thanks for that. I reconfigured that example for interrupt endpoints and additionally call USBFS_EnableOutEP() function in the main application after copying the OUT buffer to the IN buffer (seems that this is not necessary for ISOC endpoints). The workflow is verified with USB control center application.

Now, what I'm observing is that the first IN transfer gets 32 bytes with the data sent to the OUT endpoint, and the other 32 bytes are empty. Requesting another IN transfer gets the whole buffer (I verified that the PSoC got the full 64 bytes into the IN buffer within a single OUT transaction). I attached a screenshot of the USB control center window. I can reproduce this behaviour also in a small C# application: requesting 64 bytes from IN endpoint with XferData() function fills 32 bytes of a 64 byte buffer, a second call to the function gets the remaining 32 bytes.

So, I assume it is related to the 32 byte size of the endpoint buffer in PSoC when using DMA. But how to detect if the whole transfer has completed on both sides (PC application and PSoC)?

Regards

pastedImage_1.png

0 Likes

Just an update, figured out why two IN transfers were needed: it seems that the above issue is really related to the 32 byte DMA chunk size. In the main() for-loop, using a "data ready" flag to indicate that the whole buffer has been copied from OUT to IN endpoint buffer and making the call to LoadInEP() function only if this flag has been set (along with checking if the IN endpoint is ready, of course) transfers the whole buffer in one single transfer. Verified this behaviour in control panel application.

Keep in mind, when doing it this way, the IN endpoint is not re-armed (because LoadInEP() will only be called when the above mentioned flag is set), therefore a second IN transfer will result in an endpoint error in control panel application. Maybe this can be overcome by either using the endpoint exit callback instead of the entry callback or by checking the endpoint state if it's empty when copying the buffer.

Don't forget to call EnableOutEP() function if you're using interrupt or bulk OUT endpoints (as already mentioned, it seems that this is not needed for isochronous endpoints provided in the original example) after copying the buffer.

Hope this helps others trying to get into the mysteries of USBFS component with auto-DMA. Too bad that there are no better examples provided I find it's quite hard to understand the component datasheet regarding this, other Cypress examples are much more detailed and helpful.

Anyway, I don't give up! Next steps are figuring out the USB DMA buffers, currently I don't see any increased speed compared to non-DMA mode. I'll report the state here.

Regards

Thanks a lot for all the updates.Actually, a thread correspond to resolution of one issue.

Please create another thread for a different issue

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

Hi anks,

attached is the modified example which enabled me to get the data within a single transfer. It also works with interrupt and bulk transfers because the OUT endpoint is re-enabled, but I have not checked if this must be removed when switching back to the original isochronous configuration.

I also tried the exit callback idea to overcome the two-IN-transfer issue, but it showed no difference. For the endpoint status check, I'm not sure if it will work, haven't tried it yet.

I agree that one thread should be used for one problem. But I'm not sure if the DMA buffer & increase speed topic should be separated. Remember, the initial topic was about how to get USB up and running with auto-DMA. I'm not sure if the buffer handling still is within the initial topic, because someone would use DMA to increase speed. There are already a few topics regarding USB & DMA, but each of them covers only "a bit of the whole byte"

I'd be glad if we get it managed to have this thread as a single point solution for all USB DMA related questions, but it would also be okay if we place links from this to other topics.

So, how should we proceed? Should I open a new thread?

Regards

0 Likes

You should create a new thread for any new topic.

0 Likes