lpcware

LPC1347 USB VCOM Loopback problem

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by dtesystems on Mon Jul 13 02:10:15 MST 2015
Hi,

I've recently switched from using microchip microcontrollers to NXP Cortex-M3 microcontrollers. One of the advantages seemed the build in USB.

While converting my communications library I noticed a problem with the USB communication, Trying the example code on the LPC Expresso 1347 devboard confirmed this error, so I'll explain it applied to these example projects.

I'm testing the robustness of the USB vcom interface by dumping 60 characters long data on the VCOM port in loopback mode with

1) usbd_rom_cdc_uart (with rx and tx of the USART bridged of course) -> No problem what so ever
2) usbd_rom_cdc (which is an example of a vcom loopback program) -> characters are lost during transmission

I haven't made any changes to the code.

I'm using LPCXpresso v7.8.0 with all the latest versions of the examples.
I'm using this terminal-app sites.google.com/site/terminalbpp and sending this string once every second.

[color=#900]012345678901234567890123456789012345678901234567890123456789 with +CR checked[/color]

[img]https://googledrive.com/host/0B3SVyKJMOKikfllOUkpVVHVIM0lyeElvSWNSMnhpbjFFSExrX2tXbjA4NTdvLUlUdnM1U28/TerminalApp.jpg[/img]

As you can see, characters are lost during transmission. I'm sending a character length below the RX and TX buffer length. When example (1) handles this string, there is a double interrupt used. One for the USB and one for the USART, without any problems.

I think it has something to do with the critical sections in the cdc_vcom.c code, where the USB interrupt gets disabled during a short time.

vcom_bread:

/* Virtual com port buffered read routine */
uint32_t vcom_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(USB0_IRQn);
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(USB0_IRQn);
}
return cnt;

}


vcom_read_req:

/* Virtual com port read routine */
ErrorCode_t vcom_read_req(uint8_t *pBuf, uint32_t len)
{
VCOM_DATA_T *pVcom = &g_vCOM;

/* check if we queued Rx buffer */
if (pVcom->rx_flags & (VCOM_RX_BUF_QUEUED | VCOM_RX_DB_QUEUED)) {
return ERR_BUSY;
}
/* enter critical section */
NVIC_DisableIRQ(USB0_IRQn);
/* if not queue the request and return 0 bytes */
USBD_API->hw->ReadReqEP(pVcom->hUsb, USB_CDC_OUT_EP, pBuf, len);
/* exit critical section */
NVIC_EnableIRQ(USB0_IRQn);
pVcom->rx_flags |= VCOM_RX_DB_QUEUED;

return LPC_OK;
}


vcom_read_cnt:

/* Gets current read count. */
uint32_t vcom_read_cnt(void)
{
VCOM_DATA_T *pVcom = &g_vCOM;
uint32_t ret = 0;

if (pVcom->rx_flags & VCOM_RX_DONE) {
ret = pVcom->rx_count;
pVcom->rx_count = 0;
}

return ret;
}

/* Virtual com port write routine*/
uint32_t vcom_write(uint8_t *pBuf, uint32_t len)
{
VCOM_DATA_T *pVcom = &g_vCOM;
uint32_t ret = 0;

if ( (pVcom->tx_flags & VCOM_TX_CONNECTED) && ((pVcom->tx_flags & VCOM_TX_BUSY) == 0) ) {
pVcom->tx_flags |= VCOM_TX_BUSY;

/* enter critical section */
NVIC_DisableIRQ(USB0_IRQn);
ret = USBD_API->hw->WriteEP(pVcom->hUsb, USB_CDC_IN_EP, pBuf, len);
/* exit critical section */
NVIC_EnableIRQ(USB0_IRQn);
}

return ret;
}


I can't seem to figure out why this goes wrong and how I can solve this. Since the USB ROM driver takes care of the filling of the IN_EP and the reading of the OUT_EP and the vom read/write functions of the opposite, I would expect the they didn't conflict with one and other.

By changing the main loop to following code, I can reduce the failure rate from 1/120 to 1/30000 on a 5 minute test. Which is already better but still not what I get with example 1 (0 failures on a 30min test at 100ms send interval).

changed main loop:

while (1) {
/* If VCOM port is opened echo whatever we receive back to host. */
if (vcom_connected() && g_vCOM.rx_count ) {
rdCnt = vcom_bread(&g_rxBuff[0], 256);
if (rdCnt) {
vcom_write(&g_rxBuff[0], rdCnt);
}
}
/* Sleep until next IRQ happens */
__WFI();
}


Can anybody help me with this?

Outcomes