Reads and Writes using the USBDAPI on lpc43xx

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

Reads and Writes using the USBDAPI on lpc43xx

1,034 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Sun Oct 26 08:38:50 MST 2014
Hi,

I am trying to make UART styled interfaces for the USB Virtual COM on my lpc43xx device I mean actually migrating from 43xx's UART to virtual COM  method using USB.

If we look at the USBD APIs provided ,
I have the following queries w.r.t. USB driver functions

1.when it comes to things needed on a UART like  Send a byte, Receive a byte , Send a block of bytes  over USB Virtual COM

using both ways - buffered mode and non buffered. does anyone have some suggestions on this?

What I see is that the ReadEP and WriteEP are the APIs provided by the USBD to do this . But I want to know how it is really to be used.

How could the ReadEP be used to receive a byte over virtual COM and WriteEP used to transmit a single byte over Virtual COM and if I want to send a big block of data also, how to use these APIs. I am also considering that I need to handle buffered method also.

Can anyone point to some piece of code to do this kind of UART styled methods for 43xx Virtual COM?


2. I have a UART Rx ISR that handles some functionality in my current device and I want to move it to the USB's ISR.
   But the USB ISR is not available to the User to modify and not exposed to user app.

   In this case where can this functionality present in my current UART's RX ISR put in the case of USB's Virtual COM port.
   For example , can I move this Rx functionality into Bulk IN Handler or OUT handlers?

3.In the CDC VCOM exampel there is a structure for the VCOM data having members of type USBD_HANDLE_T  like handle to CDC class and handle to USBD
  and some pointers to TX Buffr and RX Buffer.

  Is it a must to maintain this VCOM structure in this way or can I make each one of the members of this structure as  global variables in my implementation?

4. Lastly, If one uses USB1 and wants to use same sources for  USB0 on lpc43xx , does anything change apart from clockmuxing and PLL during initialisation?
   Are there any other changes like Patches or Errata associated with the USB0 on the lpc433x?

 
Thanks in advance,


Labels (1)
0 Kudos
7 Replies

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Wed Nov 05 09:25:32 MST 2014
Hi,

Ok, lets first talk only about Rx .

[What is "the above routine"? ]

the above routine means the function VCOMBRead in the example
/* USB buffered read routine */
uint32_t usb_bread(uint8_t *pBuf, uint32_t buf_len)
{
VCOM_DATA_T *pVcom = &g_vCOM;
uint16_t cnt = 0;
/* read from the default buffer if any data present */
if (pVcom->rx_count) {
cnt = (pVcom->rx_count < buf_len) ? pVcom->rx_count : buf_len;
memcpy(pBuf, pVcom->rx_buff, cnt);
pVcom->rx_rd_count += cnt;

/* enter critical section */
NVIC_DisableIRQ(LPC_USB_IRQ);
if (pVcom->rx_rd_count >= pVcom->rx_count) {
pVcom->rx_flags &= ~VCOM_RX_BUF_FULL;
pVcom->rx_rd_count = pVcom->rx_count = 0;
}
/* exit critical section */
NVIC_EnableIRQ(LPC_USB_IRQ);
}
return cnt;
}

I was looking for a function that just returns the the last character read whilst the above returns number of bytes received.

[I think the "buffered read" in the example (I don't have it in front of me) can't return the last read character, because it hasn't yet completed the read, just invoked it.]

whats the best way to return the last character in my case?


See my original example code, which does use ReadEP. Once you've recovered the buffer contents using that call, you can return the last read character, if that is what you want to do.

do you mean in EVT_OUT case if we call ReadEP like in your code , that is sufficient ? I have also done it same way .

But in addition to this EVT_OUT case in my Bulk OUT Handler I also have a function to do Buffered Read ( see the usb_bread I posted above)

[you can return the last read character, if that is what you want to do.]

can you tell me how to do this , do you have a piece of code.


[What function? ]

I mean this usb_bread function works in tandem with the EVT_OUT case is what I understand , controls comes into the EVT_OUT and goes into the usb_bread  routine in the example (lpcopen_2_12_keil_iar_ngx_xplorer_4330) cdc_vcom  on lpcopen site.


I also post my code for you just in case you want to know how I am trying to implement.

Cheera
0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Wed Nov 05 09:25:29 MST 2014
Hi,

Ok, lets first talk only about Rx .

[What is "the above routine"? ]

the above routine means the function VCOMBRead in the example
/* USB buffered read routine */
uint32_t usb_bread(uint8_t *pBuf, uint32_t buf_len)
{
VCOM_DATA_T *pVcom = &g_vCOM;
uint16_t cnt = 0;
/* read from the default buffer if any data present */
if (pVcom->rx_count) {
cnt = (pVcom->rx_count < buf_len) ? pVcom->rx_count : buf_len;
memcpy(pBuf, pVcom->rx_buff, cnt);
pVcom->rx_rd_count += cnt;

/* enter critical section */
NVIC_DisableIRQ(LPC_USB_IRQ);
if (pVcom->rx_rd_count >= pVcom->rx_count) {
pVcom->rx_flags &= ~VCOM_RX_BUF_FULL;
pVcom->rx_rd_count = pVcom->rx_count = 0;
}
/* exit critical section */
NVIC_EnableIRQ(LPC_USB_IRQ);
}
return cnt;
}

I was looking for a function that just returns the the last character read whilst the above returns number of bytes received.

[I think the "buffered read" in the example (I don't have it in front of me) can't return the last read character, because it hasn't yet completed the read, just invoked it.]

whats the best way to return the last character in my case?


See my original example code, which does use ReadEP. Once you've recovered the buffer contents using that call, you can return the last read character, if that is what you want to do.

do you mean in EVT_OUT case if we call ReadEP like in your code , that is sufficient ? I have also done it same way .

But in addition to this EVT_OUT case in my Bulk OUT Handler I also have a function to do Buffered Read ( see the usb_bread I posted above)

[you can return the last read character, if that is what you want to do.]

can you tell me how to do this , do you have a piece of code.


[What function? ]

I mean this usb_bread function works in tandem with the EVT_OUT case is what I understand , controls comes into the EVT_OUT and goes into the usb_bread  routine in the example (lpcopen_2_12_keil_iar_ngx_xplorer_4330) cdc_vcom  on lpcopen site.


I also post my code for you just in case you want to know how I am trying to implement.

Cheera
0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by hangdog on Wed Nov 05 07:49:28 MST 2014

Quote: pra18

The example has a VCOMBRead that returns the number of bytes written and what I need is It should return the last read character.
how this can be changed .why is the ReadEP not used in the above routine ?



What is "the above routine"? You mean the line I just posted? I'm not clear if there's confusion here between the "number of bytes written" and the "last read" character. Why are we talking about write and read in the same breath, is that what you mean to say? In any case, I think the "buffered read" in the example (I don't have it in front of me) can't return the last read character, because it hasn't yet completed the read, just invoked it.

See my original example code, which does use ReadEP. Once you've recovered the buffer contents using that call, you can return the last read character, if that is what you want to do. If that's not an answer, then I'm sorry but I've not understood the question :).


Quote:

Also what I am unable to understand is this function does not make any call to the ReadEP also. but in EV_OUT in the Bulk handler it gets called
which means VCOMBRead does all the buffered reads and EV_OUT calls Read EP ? what is the relationship between these 2 things?



What function? As I mentioned above, I don't understand this relationship either. As far as I can see it's not documented. Nonetheless, the example code I gave seems to work on the RX side - don't ask me to explain exactly why. And on the TX side, a call to WriteEP seems to be all that is required.

Cheers
0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Wed Nov 05 07:27:41 MST 2014

Thanks for the reply.

About the Rx only :

The example has a VCOMBRead that returns the number of bytes written and what I need is It should return the last read character.
how this can be changed .why is the ReadEP not used in the above routine ?

Also what I am unable to understand is this function does not make any call to the ReadEP also. but in EV_OUT in the Bulk handler it gets called

which means VCOMBRead does all the buffered reads and EV_OUT calls Read EP ? what is the relationship between these 2 things?

both my TX and Rx buffers are 256 sized.

Thanks,

0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by hangdog on Wed Nov 05 03:32:43 MST 2014

Quote: pra18

when I call RegisterEPHandler , I am passing NULL in the last argument of this call , is this Ok?



To my understanding, yes.


Quote: pra18

  I need to find a way how to return the last received character . But the example has a function that returns the number of bytes read
  Do you know about this?



Can you not pull out the last received character from the returned buffer? Sorry, I probably am missing your point.


Quote: pra18

I need to first see if there are characters in the Rx buffer and try to pull a character out of the buffer some thing like a Ring buffer with a head    and tail 
and also
directly go and get the received character by this call USBD_API->hw->ReadEP , is it possible ? much like the standard UART_ReceiveByte following the UART styled way.



Clearly, you can implement any such protocol in your own space, so what about reading into a buffer as discussed, and then putting the stuff above in as a layer on top of that? You could perhaps do it directly through the ROM, but I'm not clear what it would mean for the drivers at each end. I think a call to write() at the host end, for instance, would hang in the meantime. Again, perhaps I'm missing your point.


Quote: pra18

  TX:
transmit a single byte over VCOM  much like the standard UART_SendByte, it this possible and how?

also transmit a block of bytes over VCOM



I think the code in the example would allow transmission of a single byte, no? I have:

//queue buffer for sending
uint32_t bytes_sent =
USBD_API->hw->WriteEP(
g_vCOM.hUsb, USB_CDC_IN_EP,
buffer, bytes
);


And afaik it would work for a single byte, though I'm not sure I've ever tried that. Still, I'm sending buffers of an arbitrary size and it seems to work fine, so a single byte ought to work also.

Cheers
0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Wed Nov 05 03:19:33 MST 2014

Hi,

Thanks for the reply.

I now managed to get away with that Structure and use global variables , this works fine as you mentioned.
After doing this change

when I call RegisterEPHandler , I am passing NULL in the last argument of this call , is this Ok? Earlier it was a

RetVal = USBD_API->core->RegisterEpHandler(UsbdHndl, EPIndex, EP_INHandler, &g_USB);
and now it is
RetVal = USBD_API->core->RegisterEpHandler(UsbdHndl, EPIndex, EP_Handler, NULL);

2. My NAK case looks like below.

case USB_EVT_OUT_NAK:
  /* queue free buffer for RX */
    if ((RxFlag & (USB_RX_BUF_FULL | USB_RX_BUF_QUEUED)) == 0)
      {
      USBD_API->hw->ReadReqEP(UsbdHandle, USB_CDC_OUT_EP, RxBuff, RX_BUFFER);
      RxFlag |= USB_RX_BUF_QUEUED;
      }


3. As you suggest, I can move the Reception ISR functionality of the UART into my EVT_OUT handler.

4 Main Problem:
 
  RX:
  
  I need to find a way how to return the last received character . But the example has a function that returns the number of bytes read
  Do you know about this?

  In the example, There is also a buffered Read routine that returns number of bytes read.

I need to first see if there are characters in the Rx buffer and try to pull a character out of the buffer some thing like a Ring buffer with a head    and tail 

and also

directly go and get the received character by this call USBD_API->hw->ReadEP , is it possible ? much like the standard UART_ReceiveByte following the UART styled way.

       
  TX:
transmit a single byte over VCOM  much like the standard UART_SendByte, it this possible and how?

also transmit a block of bytes over VCOM

Does there any example to do this kind of TX and RX for the USB CDC ,

Can anyone point to a piece of code that could help get going?

Thanks in advance,



0 Kudos

672 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by hangdog on Thu Oct 30 13:01:13 MST 2014
1) I found the VCOM example a little confusing. I think it is showing you several ways of getting the job done, but as a result I found it difficult to see which bits interacted with which other bits. Anyway, in the end it was simple.

2) You don't have the ISR, but the ReadEP and WriteEP are called when the ISR is fired. So you can put your handlers in those functions, as you suggest. I mean, you could hook the ISR too (you have the _isr() itself) but I didn't need to.

3) I had exactly the same question. The answer is no - the structure is used only within the example, and is not specified by the driver. It's passed in as a void* only, and only to be passed back in _hdlr, to my understanding.

On the write side, you should find it's no problem. On the read side, the protocol is: when the driver receives data from the other end, it will fire EVT_OUT_NAK. You need to respond to this event and pass the driver a buffer to fill through ReadReqEP. It will then fire EVT_OUT and you will - ok, I don't quite understand this bit - pass it the buffer again through ReadEp(), and it will actually fill it. I found the docs to be nearly useless, but the example had the salient information in it, just a bit jumbled up.

Anyway, the long and short is that all the stuff in the example that happens outside of VCOM_bulk_out_hdlr you can ignore (though, naturally, leave all the setup code as is in the example). There are only two events of interest at run-time on the Rx side, and they are as described above. My robustly working code is below. Items of note:

- I'm recovering pVcom from "data". No need, you can just use the global as a valid alternative. I think they had this in the example.
- My VCOM_DATA_T has members not in the example. It belongs to you, do what you want with it.
- As you can see, the protocol is trivial, once you tease it out. Why submit the buffer twice? Don't know, but it's working so wgas.

static ErrorCode_t VCOM_bulk_out_hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
{
//for docs, start here http://goo.gl/sbKskg
VCOM_DATA_T *pVcom = (VCOM_DATA_T *) data;

switch (event)
{
case USB_EVT_OUT:
{
pVcom->recv_bytes_used = USBD_API->hw->ReadEP(hUsb, USB_CDC_OUT_EP, pVcom->recv_buffer);
#ifdef USB_VERBOSE
__debug_si("USB_EVT_OUT", pVcom->recv_bytes_used);
#endif

//mark that buffer has been used
pVcom->recv_buffer = 0;

return LPC_OK;
}

case USB_EVT_OUT_NAK:
{
//this event indicates that data is pending to be received.
//if we have been passed a buffer by the caller, we respond
//by submitting this buffer to the h/w driver for filling.
//if we have not, we just ignore this event, since there's
//nowhere for us to put the data.
//
//NB: we could buffer the data locally, to smooth things
//along, but there seems little point since it won't be
//picked up any earlier.
if (pVcom->recv_buffer && pVcom->recv_bytes)
{
//submit buffer
USBD_API->hw->ReadReqEP(hUsb, USB_CDC_OUT_EP,
pVcom->recv_buffer, pVcom->recv_bytes);

//mark this so as we don't submit it twice, we don't
//need this value anymore
pVcom->recv_bytes = 0;
}

return LPC_OK;
}
}

return ERR_USBD_UNHANDLED;
}
0 Kudos