Hello Forum! I am working on a FRDM-KL25Z dev board and hopign to have it come up as a virtual com port on a windows machine and then interact with the incoming data inside the ARM. I didn't see a straightforward example of doing a VCOM port on this processor so I started out with the USB HID example for the tower system with the same processor (Keil\ARM\Boards\Freescale\XTWR-KL25Z48M\RL\USB\Device\HID) and then copied the usb_config.c and usbd_user_cdc.c from another example (Keil\ARM\Boards\Keil\MCBSTR9\RL\USB\Device\CDC). The project compiles, I load it on the target, and then I see the virtual com port on my system (after installing the driver). I have stripped out the code from usbd_user_cdc.c to remove UART functionality. The problem I am having is when I try to open the virtual com port on the windows side. I tried 9600 baud, which seemed to be the default rate in the demo. I tried Putty and RealTerm, both applications hang when I try to open the specific com port. I was wondering if you folks had an idea what I was doing wrong or how I can begin to troubleshoot this. I have debugging access and it seems that USB works enough to identify its self on my system. I also included the CM1 usb library. I added some relevant code below. (I verified usb_config.c with the wizard and it seems to make sense) Thank you in advance!
I had to put the files on pastebin to meet the 7000 character limit
usb_config.c: http://pastebin.com/4vtczSUB usbd_user_cdc.c: http://pastebin.com/RrSrH3ML usbd_MKL25Z4.c: http://pastebin.com/D9WGuqnD
> I tried Putty and RealTerm, both applications hang when I try to open the specific com port.
These PC applications put a sequence of these requests when they open target COM port. - Get_Line_Coding - Set_Line_Coding - Set_Control_Line_State
Using a hardware bus analyzer, or a software sniffer, specify the request on which your firmware fails. It narrows down the existing range of bug on your source code.
A sniffer, which recognizes CDC, is preferable. For example,
USBlyzer - 33 days trial www.usblyzer.com/download.htm
Run USBlyzer, enable "Capture->Capture Hot-plugged" menu, and plug in your device. And then open the COM port using PC application. What kind of error do you see on the log?
Tsuneo
Below is the screen capture of what happens when I captured the hot connect. I also have the data files for both of those would be helpful. Thanks.
http://i.imgur.com/gqgN6.png
Thanks to your screenshots.
In the sniffer log, your firmware processes Get_Line_Coding and Set_Control_Line_State successfully. But It fails Set_Line_Coding response. Now that we should focus on the process of this request on your firmware.
Set_Line_Coding process should end up with call to usbd_cdc_ser_initport() (usbd_user_cdc.c), to set up UART baudrate, data bits, parity and stop bits. That is, cross reference to usbd_cdc_ser_initport() on the map file will give us some clue on the bug.
Here is a couple of map file analysis.
C:\Keil\ARM\Boards\Keil\MCB2300\RL\USB\Device\RTX\CDC\Lst\VirtualCOM.map - USB_ARM_L.lib Section Cross References usbd_cdc.o(i.USBD_CDC_GetSerialState) refers to usbd_user_cdc.o(.text) for usbd_cdc_ser_linestate Adding Veneers to the image Adding TA veneer (8 bytes, Short) for call to 'usbd_cdc_ser_linestate' from usbd_cdc.o(i.USBD_CDC_GetSerialState). Adding TA veneer (8 bytes, Short) for call to 'usbd_cdc_ser_initport' from usbd_cdc.o(i.USBD_CDC_SetLineCoding).
USB_ARM_L.lib - usbd_cdc_ser_linestate() appears cross references, but usbd_cdc_ser_initport() doesn't - Both of functions are refered over TA veneer
C:\Keil\ARM\Boards\Keil\MCB1700\RL\USB\Device\RTX\CDC\Lst\VirtualCOM.map - USB_CM3.lib Section Cross References usbd_cdc.o(i.USBD_CDC_GetSerialState) refers to usbd_user_cdc.o(.text) for usbd_cdc_ser_linestate
USB_CM3.lib - usbd_cdc_ser_linestate() appears cross references - usbd_cdc_ser_initport() is not referred from anywhere
Apparently, USBD_CDC_SetLineCoding() implementation on the library source (usbd_user_cdc.c) has a bug, which doesn't call usbd_cdc_ser_initport(), depending on compilation switch.
Unfortunately, the source code of usbd_user_cdc.c is not open. Contact to Keil for the fix of this bug.
Ah, the bug lies on USBD_CDC_SetLineCoding() in usbd_cdc.c in the library, not on usbd_user_cdc.c
Tsuneo, Thanks for all or your help. I loaded code on my target and verified that both usbd_cdc_ser_openport() and usbd_cdc_ser_initport() are called once when the unit starts up and one more time when I try to open the VCOM serial port with e.g. putty. Can you let me know what you think CM1 USB lib is not doing correctly so I can try to be more specific in the Keil service request? Also, if this is an issue where USB stack is not replying to a packet type correctly, would it be possible to modify USB interrupt service routine to route the SetLineCoding request to my own code to bypass Keil's USB lib to have correct operation? Thanks.
Unfortunately, user code can't override USBD_CDC_SetLineCoding() in the library. We have to override the caller of this routine, USBD_EndPoint0_Out_CDC_ReqToIF(), to fix this bug. Keil had once exposed the primitive version of current RL-USB in RL v4.12 This snippet derives from RL v4.12, modified to fit to current RL-USB.
#include <..\..\RL\USB\INC\usb.h> extern CDC_LINE_CODING USBD_CDC_LineCoding; extern U8 USBD_EP0Buf[]; BOOL MyUSBD_CDC_SetLineCoding(void) { USBD_CDC_LineCoding.dwDTERate = (USBD_EP0Buf[0] << 0) | (USBD_EP0Buf[1] << 8) | (USBD_EP0Buf[2] << 16) | (USBD_EP0Buf[3] << 24); USBD_CDC_LineCoding.bCharFormat = USBD_EP0Buf[4]; USBD_CDC_LineCoding.bParityType = USBD_EP0Buf[5]; USBD_CDC_LineCoding.bDataBits = USBD_EP0Buf[6]; usbd_cdc_ser_closeport(); usbd_cdc_ser_openport(); usbd_cdc_ser_initport(USBD_CDC_LineCoding.dwDTERate, USBD_CDC_LineCoding.bDataBits, USBD_CDC_LineCoding.bParityType, USBD_CDC_LineCoding.bCharFormat); return (__TRUE); } extern const U8 usbd_cdc_cif_num; extern BOOL USBD_CDC_SendEncapsulatedCommand( void ); extern BOOL USBD_CDC_SetCommFeature( U16 wFeatureSelector ); BOOL USBD_EndPoint0_Out_CDC_ReqToIF(void) { if (USBD_SetupPacket.wIndex != usbd_cdc_cif_num) return (__FALSE); switch (USBD_SetupPacket.bRequest) { case CDC_SEND_ENCAPSULATED_COMMAND: if (USBD_CDC_SendEncapsulatedCommand()) { USBD_StatusInStage(); return (__TRUE); } break; case CDC_SET_COMM_FEATURE: if (USBD_CDC_SetCommFeature(USBD_SetupPacket.wValue)) { USBD_StatusInStage(); return (__TRUE); } break; case CDC_SET_LINE_CODING: if (MyUSBD_CDC_SetLineCoding()) { USBD_StatusInStage(); return (__TRUE); } break; default: break; } return (__FALSE); }
Hi Tsuneo, I added your code to my project, started debugging, and verified that we enter MyUSBD_CDC_SetLineCoding() when trying to open the serial port with putty. The function does get called, however, I still have the same issue with cancelled Set Line Coding (oi49.tinypic.com/10iex5d.jpg). I have tried opening the port with different speeds and verified that the _initport() function gets the correct speed value, for example. I have also uploaded the capture if this will be helpful for you here: routed.net/VCOM-20121118a.ulz . Thanks again for looking into this.
View all questions in Keil forum