I installed the usb_examples/usb_device_cdc_vcom_lite/bm application on my MIMXRT1060-EVK.
When it runs, I can then run a terminal emulator on the host and see the characters echoed back.
The only issue I noticed is that when I type ESC (0x1b) into the terminal the next character is not echoed. I realize it won't echo back "clean", but I don't understand why the next character is dropped. I can type other non-printables and they work as expected. I'm running with SDK 2.7.0. I've used a few different terminal emulators and I see the same things.
Is there something special about the ESC character in this application (or perhaps in USB)?
Tx
Ok, I think I'm finally able to reproduce this problem, and it doesn't have anything to do with the ESC character. I went down that rabbit hole because my target-resident code uses ESC to trigger command line editing, so it does not echo the ESC; rather it uses it as a trigger for a different block of code.
Anyway that threw me off for far too long because I was chasing USB (confirmed by Mark to not be an issue), and I was chasing my own code (confirmed by me that it is doing what it should). It occurred to me that ESC is the only character that my code does not generate an echo back to the sender. Based on that realization, I went back to the usb_device_cdc_vcom_lite example. This example just echoes whatever character is sent. Here's a snippet taken directly from the example...
void APP_task(void)
{
usb_status_t error = kStatus_USB_Error;
if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
{
/* User Code */
if ((0 != s_recvSize) && (0xFFFFFFFFU != s_recvSize))
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < s_recvSize; i++)
{
s_currSendBuf[s_sendSize++] = s_currRecvBuf[i];
}
s_recvSize = 0;
}
if (s_sendSize)
{
uint32_t size = s_sendSize;
s_sendSize = 0;
error = USB_DeviceSendRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, s_currSendBuf, size);
if (error != kStatus_USB_Success)
{
/* Failure to send Data Handling code here */
}
}
}
}
The above code works... It simply echoes each character received from the host. The problem that I am seeing is if you add one line of code that causes any character (I picked 'Z') to NOT be echoed, then everything seems to lock up as soon as I type 'Z' at the host....
void APP_task(void)
{
usb_status_t error = kStatus_USB_Error;
if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
{
/* User Code */
if ((0 != s_recvSize) && (0xFFFFFFFFU != s_recvSize))
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < s_recvSize; i++)
{
if (s_currRecvBuf[i] != 'Z') // <<<<<< Don't echo 'Z'
s_currSendBuf[s_sendSize++] = s_currRecvBuf[i];
}
s_recvSize = 0;
}
if (s_sendSize)
{
uint32_t size = s_sendSize;
s_sendSize = 0;
error = USB_DeviceSendRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, s_currSendBuf, size);
if (error != kStatus_USB_Success)
{
/* Failure to send Data Handling code here */
}
}
}
}
Now, things work fine until I type 'Z'. After that the port seems to lock up. I've reproduced this with Putty and TeraTerm (as well as my own stuff). Is this a bug in the SDK or am I just losing my mind?
If I don't hear back from anyone in a few days I'm going to repost this with a different title 'cause it has nothing to do with ESC.
Hi
I took a quick look at the example and the problem is that when there is no transmission after a reception the reception queue is no longer ready to accept further data, meaning that the USB host is wanting to send something but the device is refusing to receive it (since it has no where to receive it to).
However if the echo is performed the transmission somehow also sets up/frees the next reception queue and then reception is possible again.
You can see it in progress by simply setting a break point on any reception and then type in some more characters at the host (the device will block them and the host will be sending PINGs all the time to inform that it wants to sent). Then let the code continue and the transmission start and then the device accepts the data (the host sends all of the queued characters that it was wanting to send in a single packet and they all get echoed in a packet back - and it continues.
What I can't say is why a transmission is necessary to allow subsequent receptions since normally the Rx and Tx are independent (the example doesn't even share the same endpoint for Rx and Tx (it uses 2 and 3) which makes it even more surprising).
Also I didn't immediately see what the Tx queue management was doing to either setup or re-enable rx queue operation but certainly this is something in the stack. You may find that the stack disables reception by default until there is a transmission or some other API command is executed to re-enable it (check the documentation) and, since the echo example is envisaged to always echo it fails when the echo is not performed. I have heard of people needing to patch the stack to do things that examples are not testing - maybe ask Erich Styger who I understand has some CDC fixes.
When I echo in the uTasker USB task I do it like this and the Rx and Tx have their own independent queues which doesn't pose such complications.
extern void USB_stack(TTASKTABLE *ptrTaskTable) // scheduled on USB reception
{
QUEUE_TRANSFER Length;
unsigned char ucInputMessage[LARGE_MESSAGE]; // reserve space for receiving messages to
while ((Length = fnRead(USBPortID_VCOM, ucInputMessage, LARGE_MESSAGE)) != 0) { // read
fnWrite(USBPortID_VCOM, ucInputMessage, Length); // echo reception back to the same USB endpoint
}
}
I find it difficult to follow the SDK stack but if you want to dive in there you need to home in on the endpoint/asynchrous list that is used for device endpoint queue control and see why it is not ready.
Regards
Mark
uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training or product development requirements
Hey Mark,
Again, thanks for the reply... For some reason the notifications for this forum always end up in my junk folder, so I end up reading them late. Glad (I guess) to hear someone else sees the same problem...
This implies to me that the SDK does not support a Virtual Com Port interface correctly.
It would be nice if the SDK developers were aware of this!!! Anyone from NXP listening!!??
Thanks Mark,
Ed
BTW...
I absolutely agree that the SDK is very difficult to follow.
Hi
I expect that your problem is that the terminal emulator(s) don't send ESCs.
Try using TeraTerm and sending a file [menu "File | Send File..] containing the sequence you want to test and also setting its file option to binary - this will send all characters.
When I test uTasker CDC in echo mode I get all binary sent and echoed back so it is not a USB restriction in any way.
Regards
Mark
uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training or product development requirements
Hey Mark,
Thanks for replying...
Yea, certainly ESC is handled differently, but that wasn't my problem.
My embedded code has a command line editor in it (triggered by ESC). There was a bug in that code that only shows up when I attempt to run in in virtual-com-port mode. So prior to isolating that problem (plus the fact that I'm not that familiar with the guts of USB), I thought maybe ESC was "special" in USB. ..
Ed