WriteEP USB

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

WriteEP USB

1,208 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by storm9113 on Thu Oct 23 02:50:51 MST 2014
Hi all,

I am working on USB transfert on LPC4357.

I used the cdc_vcom example and removed all the vcom part to only keep the init of USB and handlers and then call a WriteEP to send data to Host.

I am able to send the data but I wanted to ask 2 questions about the USB mechanism.

1- In LPCopen is this USB mechanism using CPU or is the USB module working by it own without needing CPU ressources  ?

2- If it is using CPU, how to know when a transfer is complete, I guess a completion interrupt comes out ?

For example if I try to send by this way

while(1){
g_pUsbApi->hw->WriteEP (g_hUsb, EP, (uint8_t*)buf1, size1);
__WFI();
g_pUsbApi->hw->WriteEP (g_hUsb, EP, (uint8_t*)buf2, size2);
__WFI();
}


Using this methode I can receive data on host but some data is missing.

- Am I using a wrong method ? Or do I just made an error in writeEP function ?


Thank you very much
Labels (1)
0 Kudos
9 Replies

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Thu Nov 13 23:40:14 MST 2014
Hi,

for the transfer from RAM to the USB module you will use the DMA engine of the USB module, not the GPDMA. The ROM API already sets up the DMA descriptors when you queue a packet, so there is nothing you have to to with regard to this right now. This is what NXP calls the "zero copy model" or some such. If you use SDRAM as the source nothing should change, it's just a little bit slower than from internal RAM.

For the first transfer you are indeed restricted to Master 0 of the GPDMA, just as you said.

Mike
0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by storm9113 on Thu Nov 13 02:47:17 MST 2014
Hi everyone,

Thank you for your advices Mike,

I am now studiying the DMA transfer to understand the whole transaction.

So there is a Master 0 and a Master 1 Bus, where only the 0 can access SGPIO.

I can't find an example with DMA transfer from a memory to a peripheral (because I guess I need to transfer data from SDRAM to USB).
If you know where I could find one..

Then I will be able to make my example work and first of all understand how it's working, it is an automatic mechanism or does it need CPU to work ?
I've read the UM so many times and still not so clear.

On my final Application I would like to get data from SGPIO and send it through USB like : SGPIO => SDRAM => USB.
But first I want to make it step by step.

So first I transfer my data from SGPIO to SDRAM with DMA Master 0, then I have to send my data from the SDRAM to the buffer data of the dTD if I am correct. For this last transfer is there a way to transfer the data without using so much cpu ? What are the possibilities ?

Thank you,

Regards

0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Fri Oct 31 03:29:02 MST 2014
Hi,

you won't find the source because these functions are part of the ROM API.
At times I wished I had the sources myself, since I've found at least one undocumented bug (does not apply here).

I understand your motivation for looking more deeply into the inner workings. But: I have written an USB stack once from scratch myself and I assure you that a working library is a lot more convenient.

With the NXP ROM library I think there are enough hooks provided to "link in" at almost any level one would want to (if neeeded).
However, the documention is on the poor side (my opinion).

There is maybe one area where you can gain something by using the registers directly and that is using the DMA of the module yourself. The DMA is fairly easy to understand and when you don't use the WriteEP()-function or the like but handle transfers yourself, you can probably have better streaming performance.
But then you need a host that can handle the bandwidth as well. At least for classes like HID or CDC the default windows class drivers are the bottleneck for now.


Regards,

Mike


0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by storm9113 on Fri Oct 31 02:48:57 MST 2014
Thank you for all this information Mike,

Last question,

Now it's working for me, I want to go to the down level functions (if it's possible) to see for example for the handlers, which registers are used, or for the WriteEP function how it is working.

But in the project I can't find the definition of WriteEP, I can only find the prototype in the header but not the source of the function.

This way I could understand more "deeply" which registers are used, and maybe evaluate in a better way exactly which ressources I need.

And maybe sometimes using directly the registers is easier than calling x functions.

Regards

0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Thu Oct 30 00:06:36 MST 2014
Hi,

this looks quite fine to me.
I have not used the CDC ROm API myself, so the next comment does not come from experience.

You register your EP handler "directly" with these two lines you added. This works but you have to specifiy the EP manually.
Now when you later change the EP number in the descriptors and forget to make same change again here it won't work again.
I think the more convenient an consistent way is to simply specify your handler when you call init().
The CDC_INIT_PARAM-struct has a member CDC_BulkIN_Hdlr for this. See p. 767 in the current UM.
Then the ROM API takes the EP index from the descriptor and you don't have to do any calculations yourself.

About that data-parameter:
You can use that or not, it is there for convenience. Every time the handler is called from the USB ROM stack it will be passed "back" to you just as you set it when you registered the handler.
So you could set up one general handler for several EP and at run time look at the data parameter to decide which EP actually triggered it.

Your occupe-variable is most likely now a global volatile one and that is fine.

Anyway, now you are set up, looks good & have fun with USB.

Mike

0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by storm9113 on Wed Oct 29 01:24:18 MST 2014
Hi Mike,

Thank you again for your reply,

Indeed I have set up everything Windows need (descriptor, drivers..), my board is recognized as I want from the computer with Bulk Endpoints.
I think I have managed it to work, I'm able to detect USB_EVT_IN and change the flag state but I still have to check if everything is ok.

Here are the lines I've added to my code :

First the CDC_BulkIN_Hdlr which check if an event IN occurs and change the flag state :
static ErrorCode_t CDC_BulkIN_Hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
{
switch (event) {
case USB_EVT_IN:
/* USB_EVT_IN occurs when HW completes sending IN packet. So clear the
    busy flag for main loop to queue next packet.
 */
occupe = 0;
break;
}
return LPC_OK;
}


Then I added 2 lines I've seen in some other examples, which (If I understand) set an index on one Physical Endpoint which will be the one we want to detect the event on. And then attach the function
CDC_BulkIN_Hdlr to it. The last parameter of RegisterEpHandler function is defined as "data Pointer to the data which will be passed when callback function is called by the stack." I need to put my flag here or my data buffer which I want to send in WriteEp ?
ep_indx = (((0x82 & 0x0F) << 1) + 1);
ret = USBD_API->core->RegisterEpHandler(g_hUsb, ep_indx, CDC_BulkIN_Hdlr, &occupe);


and then I check the connection and the flag state and send my data or not :
while (1) 
{
/* check device is configured before sending. */
if ( USB_IsConfigured(g_hUsb)) {
if (occupe == 0) {

/* Busy flag */
occupe = 1;
                        /* send data */
g_pUsbApi->hw->WriteEP (g_hUsb, EP, buffer, len); 
}
}
else 
{
/* reset busy flag if we get disconnected. */
occupe = 0;
}
        
}


With this I'm able to detect USB_EVT_IN change the flag and send my data, then on Host I have a program which print what is received on USB and I can see the send is ok. But maybe some things still incorrect in my code.
Do you see some errors ?

Thank you very much,

Regards
0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Tue Oct 28 10:22:19 MST 2014
Hi,

I assume from your description that you (want to) set up a composite device.
One of the interfaces shall then be of CDC class type and some other interface(s) of other class types.

Did you include an IAD (Interface Association Descriptor)? At least for Windows that is mandatory for the CDC/ACM interface, I think. I have once developed an USB device with one HID and one CDC/ACM interface and with the use of an IAD that was no problem.

If successful at least that interface of your device should be recognized by Windows. You will (at least until W7) also need to supply an INF-File, since the already supplied driver "usbser.sys" is not associated with the class itself, i.e. there is no default class driver loaded by the system. I have read that with W8 one can enable it as a class driver but have no personal experience yet.

Now as soon as the driver is loaded it will start to request packets from your data IN-EP. This is the IN-EP you have declared in the data class interface.
The EP_Hdlr associated with that EP should then see the events. Since initially you most probably have not queued any data, you won't see an USB_EVT_IN. You might get USB_EVT_IN_NAK, if enabled. I have not looked at the API where to enable NAK-notification, if required.

But in your case you simply set the flag initially to "transfer complete the endpoint is free", queue the first packet once you have data and then you should get the event USB_EVT_IN shortly thereafter.

If you don't see ANY event, either the configuration of your device/interface failed (check device manager) or you are watching the wrong EP.

A very helpful free piece of SW is USBVIEW.exe. It will show you how windows sees all enumerated devices and you can check there if the configuration windows sees is the same you would like to see it.

Regards,

Mike

0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by storm9113 on Tue Oct 28 01:31:32 MST 2014
Hi Mike,

Thank you for your answer,

Indeed I want to use a call back function to set a flag to say "transfer complete the endpoint is free".
The thing is I am using the cdc example but for my use I changed the class and I am working with the miscellaneous class 0xEF.
So I don't know if I should use the cdc In EP or not.

For the moment I have a simple function as CDC_BulkIn_Hdlr which check if a USB_EVT_IN occurs and set a flag.
And in the main loop if the flag is set I put it down and send data with WriteEP.
But the function CDC_BulkIn_Hdlr is never called (I don't know if I should use the USBD_API->core->RegisterEpHandler function to specify on which Endpoint I want to check the EVT)

Things are little confused in my mind.

Regards
0 Kudos

952 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Thu Oct 23 04:36:42 MST 2014
Hi,

I have not used the CDC class API of the USB ROM, but I have used the HID class with the USB ROM and the same principle should apply.

1. The USB module will transfer a packet or several packets on its own.
It has a DMA engine that supports whole tranfers (more than one packet).
However, I do *not* know how many transfers the USB ROM stack can/will queue.

2. Write to host
The information you look for ("transfer complete") is the USB_EVT_IN event. You must set up a callback-function for the CDC IN Ep (see API). This function gets called when the data has been sent and the event parameter is then set to USB_EVT_IN.
You can then either queue the next data via WriteEP() immediately in the callback function or just set a flag in a volatile variable.
Then you would wait for that variable to get set instead of the __WFI() of your code.

Regards,

Mike

0 Kudos