Please help me understand LPCopen CDC example

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

Please help me understand LPCopen CDC example

639 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by abonent on Sun Jan 25 12:50:14 MST 2015
Hello.
I'm using this http://www.embeddedartists.com/products/boards/lpc11u35_qsb.php board, plus LPC-Link2 and LPCXpresso v7.5.0 [Build 254] [2014-10-31] for my experiments.
I took LPCopen package http://www.lpcware.com/system/files/lpcopen_v2_03_lpcxpresso_nxp_lpcxpresso_11u37h.zip and imported nxp_lpcxpresso_11u37_usbd_rom_cdc, nxp_lpcxpresso_11u37h_board_lib and lpc_chip_11uxx_lib projects. I built it successfully and flashed on the board. The board enumerated as CDCserial device and I was able to talk to it using serial terminal, strings sent to it were correctly echoed back. So far everything OK.

When my mainline code looks like this:
while (1)
{
//dly_ms(1);
LPC_GPIO->NOT[0]  = (1<<7);
if (vcom_connected() != 0)
{
rdCnt = vcom_bread(&g_rxBuff[0], 256);
if (rdCnt)
vcom_write(&g_rxBuff[0], rdCnt);
}
}

all data are correctly echoed. However, once I uncomment the dly_ms function (doing simple delay loop for approximately 1ms), most of the characters is missing. From message "Hello world" I usually receive only "d" or "ld" characters.
I plan to use the LPC device to process data from stream od characters and the delay represents time delay caused by data processing. I expect the incomming data to be NAK-ed while the LPC is busy with data processing (should be done in USB interrupts) and I don't care about slow data transfer, but lost data is problem. I put breakpoint at the vcom_write function and the received data (to send back to PC) is the one or two symbols I receive in terminal, so it looks like the data is lost at the receiving part of code.
I took a look at vcom_bread function and it looks like it just reads data from pVcom structure, filled by VCOM_bulk_out_hdlr handler and it looks a bit more complicated and honestly I don't understand it much:
/* VCOM bulk EP_OUT endpoint handler */
static ErrorCode_t VCOM_bulk_out_hdlr(USBD_HANDLE_T hUsb, void *data, uint32_t event)
{
VCOM_DATA_T *pVcom = (VCOM_DATA_T *) data;
switch (event) {
case USB_EVT_OUT:
pVcom->rx_count = USBD_API->hw->ReadEP(hUsb, USB_CDC_OUT_EP, pVcom->rx_buff);
if (pVcom->rx_flags & VCOM_RX_BUF_QUEUED) {
pVcom->rx_flags &= ~VCOM_RX_BUF_QUEUED;
if (pVcom->rx_count != 0) {
pVcom->rx_flags |= VCOM_RX_BUF_FULL;
}

}
else if (pVcom->rx_flags & VCOM_RX_DB_QUEUED) {
pVcom->rx_flags &= ~VCOM_RX_DB_QUEUED;
pVcom->rx_flags |= VCOM_RX_DONE;
}
break;
case USB_EVT_OUT_NAK:
/* queue free buffer for RX */
if ((pVcom->rx_flags & (VCOM_RX_BUF_FULL | VCOM_RX_BUF_QUEUED)) == 0) {
USBD_API->hw->ReadReqEP(hUsb, USB_CDC_OUT_EP, pVcom->rx_buff, VCOM_RX_BUF_SZ);
pVcom->rx_flags |= VCOM_RX_BUF_QUEUED;
}
break;
default:
break;
}
return LPC_OK;
}

I see that when OUT event on givent endpoint happens, the pVcom->rx_buff is overwritten by new data, regardless whether it was read or not. Honestly, I don't understand the meaning of flags VCOM_RX_BUF_QUEUED, VCOM_RX_BUF_FULL, VCOM_RX_DB_QUEUED and VCOM_RX_DONE, as well as what the handler actually does. I looked into documentation and it was quite sparse
static ErrorCode_t VCOM_bulk_out_hdlr ( USBD_HANDLE_T  hUsb,
void *  data,
uint32_t  event 
) 
static

Definition at line 65 of file cdc_vcom.c.

and explanation of the flags I just can't find.

TLDR version: I have no idea why my data are lost when I don't read it very often from main loop. The documentation didn't help me much.

Could anybody, please, help me with understanding why the data from OUT transaction are lost when vcom_bread function is not called often and how to fix the code?
Labels (1)
0 Kudos
2 Replies

424 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by abonent on Wed Dec 30 13:15:24 MST 2015

Quote: SeleneSW
Hi abonent,


SeleneSW - thank you much for your response. Since it is almost year since I tried to solve this problem, I don't remember very much details.


Quote: SeleneSW
While implementing USB CDC communication in one of our projects, I had your problem too.
After some investigation, as you saw, I've found that the VCOM_bulk_out_hdlr function is broken in the sense that overrides the pVcom->rx_buff buffer with new data every time the interrupt is called.
In this way if the vcom_bread function is not called fast enought we lose some packets.
I've managed to fix this, implementing a check inside the VCOM_bulk_out_hdlr function, and if there is no space in the buffer for the new packet, I just don't do the USBD_API->hw->ReadEP call (with the side effect that the interrupt will not be called any time soon, because the USB peripheral has no space),



So, not reading USBD_API->hw->ReadEP is safe and doesn't have any adverse effects? I barely remember setting up simple state machine and checking room in data buffer and once it was full, I didn't do EP reading, hoping in NAKed packets, but I recall it locked down virtual COM port. Perhaps my implementation was wrong, so I can try to reimplement it again.


Quote: SeleneSW

and later in the vcom_bread when I make room reading data, I call the USBD_API->hw->ReadEP enabling the interrupt again.


Well, maybe this is my problem, I didn't perform EP reading in vcom_bread function, but expected the VCOM_bulk_out_hdlr to be called again - seems like I was wrong. Thank you for this information, I'll try to find the old code and rework it.
0 Kudos

424 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by SeleneSW on Wed Dec 30 09:22:32 MST 2015
Hi abonent,

While implementing USB CDC communication in one of our projects, I had your problem too.
After some investigation, as you saw, I've found that the VCOM_bulk_out_hdlr function is broken in the sense that overrides the pVcom->rx_buff buffer with new data every time the interrupt is called.
In this way if the vcom_bread function is not called fast enought we lose some packets.
I've managed to fix this, implementing a check inside the VCOM_bulk_out_hdlr function, and if there is no space in the buffer for the new packet, I just don't do the USBD_API->hw->ReadEP call (with the side effect that the interrupt will not be called any time soon, because the USB peripheral has no space), and later in the vcom_bread when I make room reading data, I call the USBD_API->hw->ReadEP enabling the interrupt again.
0 Kudos