MCU User Forum
  USB
  USB CDC implementation for 'F32x

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone! next newest topic | next oldest topic
Author Topic:   USB CDC implementation for 'F32x
Tsuneo
Member
posted July 19, 2006 09:38 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
USB CDC (Communication Device Class) implementation for 'F32x and 'F34x

This code is an implementation of CDC ACM (Abstract Control Model) discussed in the topic, "F320 USB".
(Sorry Don, it takes longer to implement it than expected.)

USB_CDC_skeleton_14.zip

History
    v1.0 (July 19, 2006)
        Initial release
    v1.1 (July 21, 2006)
        Added support for 'F34x
        Renamed the project and file names, not to include 'F32x_'
        Delete Low-speed support
            Actually, low-speed is achieved using interrupt endpoints instead of bulk.
            But it is out of spec for CDC ACM.
        The temporary buffer in line coding handling was moved
        from unused USB FIFO to IDATA, for 'F34x compatibility
    v1.2 (Aug 14, 2006)
        Revised USB interrupt setting after USB bus reset.
        Deleted 'reset data toggle' code in Set_Configuration, because it is done
        by USB bus reset (from personal communication with SiLabs)
    v1.3 (Aug 18, 2006)
        Optimized setup stage handling in the device request handler.
        This optimization reduces the code size about 150 bytes for Keil,
        230 bytes for SDCC
    v1.4 (Sep 5, 2006)
        Optimized class-specific request handling. As the check of interface number is common,
        it is done before dispatcher.
        Reviced Usb0_Init in USB_Main.c : enabled USB reset interrupt.
        Reviced Set_Configuration in USB_Standard_Requests.c : recovered 'reset data toggle'
        Reviced Usb_Suspend in USB_ISR.c, to match to the peripheral initialization in Port_Init.
        Commented out USB Resume interrupt handling, It does nothing in this implementation.
        Bug fix: F32x occasionally fails SET_LINE_CODING on high-speed hub.
        This bug was fixed by deleting DATAEND of SUEND event handling in Handle_Setup (USB_ISR.c)


Applying CDC ACM, the device is recognized as 'virtual' COM port using built-in device driver, in most of major OS including Windows, MacOS and Linux.

In this code, the USB side is fully implemented, but no UART is attached. Instead, support routines to connect peripherals to it are provided. The purpose of this implementation is to place a start point for further modification. For simple USB-serial conversion, I recommend you to use existing USB-serial chips.

The code is based on SiLabs USB_INT (release 1.3). Though the original comments by SiLabs are preserved to respect their work, this implementation has no relation to them. (I also have no relation to SiLabs ) Use it on your own risk as usual.

Thanks Patryk, your advices in "Optimization of SiLabs USB examples in code size" are fully reflected to this implementation. Also, thanks Maarten and Frieder, your suggestions in the topic, "Help to convert sample code of USB_INT to compile under SDCC" help me much on this implementation.

Tsuneo


Note
A) Compilation
This code was checked on SiLabs 'F320 and 'F340 dev board.
Select one of appropriate include file for the device in 'USB_CDC_Type.h'

#include <c8051f320.h>
//#include <c8051f340.h>

The code is compiled with Keil or SDCC. The conditional compilation on the code automatically detects the compiler. The work space files, 'Keil_USB_CDC_skeleton.wsp' and 'SDCC_USB_CDC_skeleton.wsp', are provided for SiLabs IDE.

SMALL memory model
Code size
      Keil full version and 4K eval (SiLabs)
        3754 (F320 and F340) bytes
      SDCC 2.6.0 #4290 (20060718-4290)
        4105 (F320 and F340) bytes

USB spec compliance was checked using USBCV R1.3 beta on Chapter 9.

Unfortunately, 'F326/7 cannot be supported because these devices has only two EP other than EP0.


B) Installation
Download the code to 'F320DK and connect the board to an USB port of your PC. 'New Hardware' wizard asks you to locate an INF(.inf) file. Specify the 'CDC_ACM.inf' in the INF folder in the zip file.

When installed successfully, the device appears on your PC as a COM port.


C) Demonstration
This implementation simply echoes back the TX output of COM port to RX port. Using a terminal software, such as RealTerm, you can confirm it by keyboard and file transfer.

Following transfer speed was observed on loop back, simultaneous bi-direction transfer (WinXP SP2).

       SYSCLK  Speed (Kbytes/sec)
F320DK 24MHz 150
F340DK 48MHz 280

Though I didn't check about transfer speed of single direction transfer, it'll be much faster, from the record of bus analyzer.

LEDs and SWs on the 'F320DK are connected to RTS, DTR and CTS, DSR, respectively. But RTS and CTS don't work well because usbser.sys on Windows is weird as noted below.


D) Modification
VID/PID of this implementation was bought from VOTI to puslish it on the web. You can use this VID/PID in your lab, but get your own VID/PID when you distribute your products. VID/PID is defined in 'USB_Descriptor.h' and INF file.

TX and RX from PC over USB are attached to ring buffers respectively in 'USB_CDC_UART.c'.
The data received from PC is stored in TX buffer.
'bit TXReady' shows the TX buffer has any data
'UINT TXcount' holds the number of bytes on the TX buffer.
'BYTE COMGetByte(void)' retrieves a byte from the TX buffer, and decrements 'TXcount'

The data sent to PC is held in RX buffer.
'bit RXReady' shows that RX buffer has room to store another data
'UINT RXcount' holds the number of bytes on the RX buffer.
'void COMPutByte( BYTE )' put the data to RX buffer.

The size and memory space allocation for the TX and RX buffer are defined in 'USB_CDC_UART.h'.

In this implementation, these output and input of ring buffers are connected directly together in the main loop, 'USB_Main.c', for demonstration. In your modification, these main stream buffers will be connected to the input and output of your peripheral.

Ring buffer is easy to use, but its speed performance is not so good. To handle an IN transfer (device -> PC) of steady transfer rate, such as ADC, a double buffer is suitable. Also when the packet size of single transfer is always the same, a double buffer works better. You can find an example of double buffer in the topic '256000 bytes/sec Isochronous transfer' on this forum.

Other than these main data transfer path, you'll need to exchange 'trigger' and 'parameters' between the device and the PC.

In 'USB_CDC_UART.c',
- The COM port setting (baudrate, data bits, stop bits, parity) from PC is received in Set_Line_Coding().
- DTR setting from PC is received in Set_Line_State().
- Break signaling from PC is received in Send_Break().
- DSR and other UART status (parity, frame error, etc.) are returned to PC in Update_Line_State().
See following 'COM session examples' how these functions on the firmware corresponds to the PC COM APIs.

These handshake signals and setting parameters are completely independent from the main data transfer path. ie. Even if you set the baudrate to either 9600 or 115200 on the PC, it has nothing to do with the transfer rate of the TX and RX. Therefore, these signals and setting parameters are used for 'command' from PC and 'reply' from the device.

Using or modifying these functions, you can connect any peripherals to PC COM port.

Turning macro POLL_READ_BYTE/POLL_WRITE_BYTE into functions saves about 310 bytes in Keil, 130bytes in SDCC. When the code size is more essential for your project than execution speed, apply this modification. To convert these macro to function, comment out these macros at the bottom of USB_Register.h.

Edit the INF file, 'CDC_ACM.inf', in the INF folder with your favorite text editor.
The VID/PID specified in the INF file must match to that of the device.
See the comments in the INF file for another points to edit.


Q and A
Q1. What are the resources of C8051F340 which are used by to implement this functionality ?
A1.
  On-chip peripherals:
  - USB0 - absolutely yes
  - Internal OSC - for USB clock with clock recovery
  - - SYSCLK: no restriction, select appropriate one for your task
  - USB0 interrupt - required, priority (high/low) - either will do

  Memories (bytes) - v1.4
  'xdata' is used for RX/TX buffer - tunable on its size and memory assignment
  KEIL - code: 3754, data: 73.5, xdata: 512
  SDCC - code: 4105, data: 0x00 - 0x46, except stack, xdata: 512

  For the demonstration only - not the absolute requirement
  - Timer2 and Timer2 interrupt
  - - To debounce the switch inputs on the dev board
  - Ports on 'F34x dev board
  - - P2.0 and P2.1 - switch
  - - P2.2 and P2.3 - LED
  The ports (P0,P1,P2) are configured to fit to the jumper setting of the dev board. But it is not the absolute requirement.

Q2. In addtion to virtual com port, can this device equip another USB functions at the same time?
A2. Unfortunately, Windows built-in device driver, usbser.sys, doesn't accept it.
As the USB CDC spec allows it, a custom device driver can support composite device of CDC and other USB class, such as HID, MSC. But I don't know any free device driver which replaces usbser.sys. You must make it by yourself, or buy a commercial one.


E) Weird usbser.sys
The usbser.sys (built-in device driver of Windows) is weird in several points.

WinXP SP2, usbser.sys (5.1.2699.2180)

When the transfer size is just the multiple of 64 bytes (max packet size of bulk IN EP), ReadFile doesn't finish until zero length packet is received, even if the actual transfer size is equal to the requested size.

The requests issued (or not issued) by usbser.sys are as follows. You'll find how usbser.sys is weird.


a) Just after device configuration
GET_LINE_CODING
SET_CONTROL_LINE_STATE(0x00) - RTS:0, DTR:0

b) COM session: example 1
RTS doesn't match between PC and device until SetCommState.
Even though usbser.sys issues SET_CONTROL_LINE_STATE(0x00) at the configuration,
its internal setting (fRtsControl field of DCB) doesn't reflect it.
GetCommState and SetCommState issues redundant requests.
CloseHandle issues redundant SET_CONTROL_LINE_STATE

- CreateFile
no request
- PurgeComm
no request
- GetCommState
GET_LINE_CODING
GET_LINE_CODING
- change baudrate on DCB
fRtsControl is '1' as default when DCB is read out.
- SetCommState
GET_LINE_CODING
GET_LINE_CODING
SET_LINE_CODING
GET_LINE_CODING
SET_CONTROL_LINE_STATE(0x02) - RTS:1, DTR:0
SET_LINE_CODING
GET_LINE_CODING
- ReadFile/WriteFile
bulk transfer
- CloseHandle
SET_CONTROL_LINE_STATE(0x02) - RTS:1, DTR:0

c) COM session: example 2
EscapeCommFunction( SETRTS ) and EscapeCommFunction( CLRRTS ) issue no request.
Only the fRtsControl field of DCB seems to be able to set/reset RTS

- CreateFile
no request
- EscapeCommFunction( SETDTR )
SET_CONTROL_LINE_STATE(0x01) - RTS:0, DTR:1
- EscapeCommFunction( CLRDTR )
SET_CONTROL_LINE_STATE(0x00) - RTS:0, DTR:0
- EscapeCommFunction( SETRTS )
no request
- EscapeCommFunction( CLRRTS )
no request
- EscapeCommFunction( SETBREAK )
SEND_BREAK(0xFFFF)
- EscapeCommFunction( CLRBREAK )
SEND_BREAK(0x0000)
- SetCommBreak
SEND_BREAK(0xFFFF)
- ClearCommBreak
SEND_BREAK(0x0000)
- GetCommModemStatus
no request - (because the status is returned by the interrupt EP)
- ClearCommError
no request - (because the status is returned by the interrupt EP)
- CloseHandle
SET_CONTROL_LINE_STATE(0x00) - RTS:0, DTR:0

d) COM session: example 3
CTS is always asserted regardless of actual input.

- CreateFile
no request
- GetCommModemStatus
stat = 0x10 (CTS: 1, DSR: 0)
- set DSR to 1
- GetCommModemStatus
stat = 0x30 (CTS: 1, DSR: 1)
- set DSR to 0
- GetCommModemStatus
stat = 0x10 (CTS: 1, DSR: 0)
- set CTS to 1
- GetCommModemStatus
stat = 0x10 (CTS: 1, DSR: 0)
- set CTS to 0
- GetCommModemStatus
stat = 0x10 (CTS: 1, DSR: 0)
- CloseHandle
SET_CONTROL_LINE_STATE(0x00) - RTS:0, DTR:0

[This message has been edited by Tsuneo (edited September 05, 2006).]

IP: Logged

Bert
Member
posted July 21, 2006 01:22 AM     Click Here to See the Profile for Bert   Click Here to Email Bert     Edit/Delete Message
Thanks Tsuneo,
It is a very useful addition to the collection examples for the F320 I already have.

IP: Logged

Tsuneo
Member
posted July 21, 2006 04:11 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Updated to v1.1 - Added 'F34x support
Download it from the link on the first post (the link was revised).

Tsuneo

IP: Logged

Tsuneo
Member
posted August 14, 2006 09:57 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Updated to v1.2
- Fixed a minor bug on the interrupt setting for USB endpoints after USB bus reset. The endpoints interrupt was enabled uselessly after USB bus reset, though it is ignored by the USB ISR. Fixed it.
- Deleted 'clear toggle' code from the endpoint initialization on Set_Configuration, because it is done by USB bus reset - according to the reply from SiLabs.

Tsuneo

IP: Logged

Tsuneo
Member
posted August 19, 2006 12:38 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Updated to v1.3
- Optimized the setup stage handling of the standard and class request. This optimization reduces the code size about 150 bytes for Keil, 230 bytes for SDCC

Tsuneo

IP: Logged

egawtry
Member
posted August 23, 2006 11:41 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
I tried compiling this with SiLabs IDE and with Keil, and all I get is "USB Device Not Recognized". Pulling it up with UVCView, it says "Device not Enumerated".

The one change I made was changing the include file from 320 to 340.

Anyone with ideas?

Thanks,
-Erik

[This message has been edited by egawtry (edited August 23, 2006).]

IP: Logged

Tsuneo
Member
posted August 23, 2006 09:27 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Erik,

Thank you for trying it.
It works fine on my side on SiLabs 'F340 dev board also.

CDC ACM requires INF file to install it to Windows, unlike HID.
When you connect the board to a PC first, the PC pops up the New Hardware dialog. Specify the INF file, 'CDC_ACM.inf' in the INF folder.

Tsuneo

IP: Logged

egawtry
Member
posted August 24, 2006 11:25 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
What I am saying is that I don't even get the new hardware dialog. All I get is the error message.

I tried forcing the INF anyway, but Windows refused to attach it.

To see if it is my board, does anyone have a HEX to post so I can test it?

Thanks,
-Erik

[This message has been edited by egawtry (edited August 24, 2006).]

IP: Logged

Tsuneo
Member
posted August 24, 2006 10:50 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
This is the hex file for 'F34x.
keil_usb_cdc_skeleton.hex

The compile switch for Keil is almost default,
Compiler: DB OE CD
Linker: RS(256)

The jumpers on the 'F340 dev board are as follows. (from top to down)
- J17: plugged
- J16: plugged
- J12: all jumpers are plugged
- J8 : VREGIN - VDD
- J19: REG_IN - P1_PWR
- J15: plugged
- J11: plugged
- J10: plugged
- J7 : plugged

All other jumpers are unplugged.
This jumper setting means the board is powered by the wall-mount supply.

Tsuneo

IP: Logged

egawtry
Member
posted August 25, 2006 11:46 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Huh. I get the same thing with that HEX file. My hardware must be messed up. I will diagnose and post my results.

Thanks,
-Erik

IP: Logged

Patryk
Member
posted August 31, 2006 03:22 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
Hello, Tsuneo!

I was playing happily with version 1.1 before my holidays, now I'm back and voila - 1.3. Got some questions about 1.1, but that later. Now something about 1.3.

1. USB Reset interrupt (and others except Suspend) is disabled in Usb0_Init() and enabled in Usb_Reset() (in interrupt handler). I didn't run 1.3 yet on my hardware, so I cannot say if it works. I believe it does since you surely checked it :-) It may work: there is 10ms recovery interval after reset signalling and this may fire Suspend interrupt. Since Reset is polled first in ISR, then all is probably done in correct sequence. Anyway I opt for enabling Reset, Suspend and Resume interrupts in Usb0_Init(). SOF interrupt enable may stay in Usb_Reset() to avoid mess until all is configured.
BTW I have modified your implementation to use interrupts for EP2 IN/OUT. It works well despite...disabled EP2 interrupts! :-) I discovered this when investigating disabled Reset int in 1.3. SOF int must have done the job! Your firmware is bullet proof - works despite stupid bugs introduced by others :-)

2. Removing 'reset data toggle' code in Set_Configuration() violates USB spec.
p. 256, 9.4.5 Get Status
"The Halt feature is reset to zero after either a SetConfiguration() or SetInterface() request even if the requested configuration or interface is the same as the current configuration or interface."

Note that that device may be configured/unconfigured (SET_CONF(1)/SET_CONF(0) requests issued) many times without USB reset, at least when controlled by other driver than MS one.

BTW: MS Platform SDK says that applications are receiving notifications for ports (WM_DEVICECHANGE\DBT_DEVICEARRIVAL\DBT_DEVTYP_PORT\"COMx") without any registration. I confirmed it with CP2102, FTDI and Prolific. This is not the case with this example - only WM_DEVICECHANGE\DBT_DEVNODES_CHANGED messages are received. Any clues?

Edited: I'll repeat that turning POLL_READ_BYTE/POLL_WRITE_BYTE into functions saves 150bytes, at least under SDCC 2.5.0. No need to make them reentrant (no overlay will do), since they may be safely called only with ints disabled.

Regards,
Patryk

[This message has been edited by Patryk (edited August 31, 2006).]

IP: Logged

Patryk
Member
posted September 05, 2006 05:47 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
Tsuneo, I'm waiting for your response to 1, 2 and WM_DEVICECHANGE.

IP: Logged

Tsuneo
Member
posted September 05, 2006 09:43 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Patryk,

Sorry for my late response.
I found a bug - "'F32x Fails on High-Speed Hub", and it took my free time in these days. As I finished the fix and test, I'll post the update soon.

"1. USB Reset interrupt (and others except Suspend) is disabled in Usb0_Init() and enabled in Usb_Reset() (in interrupt handler)."

Actually, it works.
The USB Reset interrupt is enabled when the SIE receives bus reset. And wow, it evokes the USB Reset interrupt even though it is disabled before bus reset. But it's tricky. I revised it on v1.4.


"2. Removing 'reset data toggle' code in Set_Configuration() violates USB spec.

Surely, Set_Configuration may be issued without bus reset. I recovered it on v1.4.

'Reset data toggle' isn't directly connected to 'HALT'. The USB 2.0 spec defines its handling as follows.

9.4.5 Get Status (usb_20.pdf p256)
"For endpoints using data toggle, regardless of whether an endpoint has the Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the data toggle being reinitialized to DATA0.
The Halt feature is reset to zero after either a SetConfiguration() or SetInterface() request even if the requested configuration or interface is the same as the current configuration or interface."

This sentence only means 'reset data toggle' should be done in ClearFeature(ENDPOINT_HALT). 'Halt feature' is reset to zero independently either in SetConfiguration or SetInterface. Rather, this sentence is the ground to implement it in SetConfiguration.

9.1.1.5 Configured
"Before a USB device’s function may be used, the device must be configured. From the device’s perspective, configuration involves correctly processing a SetConfiguration() request with a non-zero configuration value. Configuring a device or changing an alternate setting causes all of the status and configuration values associated with endpoints in the affected interfaces to be set to their default values. This includes setting the data toggle of any endpoint using data toggles to the value DATA0."


As of the lack of WM_DEVICECHANGE, it seems to be counted in as one of defects of usbser.sys.
"USBSER.SYS version problem. Virtual Comport questions." from USB-IF
http://www.usb.org/phpbb/viewtopic.php?t=8876
Currently I have nothing certain on this issue. The registry setting in the INF file may have any relation on this issue, but I'm not sure. Anyway, as MS doesn't open any document for usbser.sys, only trial and error can find it. As a last resort, disassembling usbser.sys by IDA Pro may be needed to confirm it.


"I'll repeat that turning POLL_READ_BYTE/POLL_WRITE_BYTE into functions saves 150bytes, at least under SDCC 2.5.0."

It's a barter of execution speed and code size. So, I'll leave it to user's choice. I've optimized the code to simplify its logic and code flow. I believe it contributes to both of speed and size.
Your suggestion was added to the modification section.

Tsuneo

[This message has been edited by Tsuneo (edited September 05, 2006).]

IP: Logged

Tsuneo
Member
posted September 05, 2006 02:26 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Updated to v1.4
- Bug fix: 'F32x fail SET_LINE_CODING on high-speed hub
- And other minor optimization and revision

Tsuneo

IP: Logged

Patryk
Member
posted September 06, 2006 05:33 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
You're right about 9.1.1.5, I missed it. I found 9.4.5 in a desperate "I have seen it somewhere" search :-)

IP: Logged

Patryk
Member
posted September 06, 2006 10:12 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
Some suggestions.

1. What for is second Delay() in Sysclk_Init()? No need according to datasheet.

2. Why SDSTL bit for EPs other than EP0 is set in Handle_EP_HALT() and not in Set_Feature()? This dalays intended CLEAR_FUTURE(HALT) effect to next SOF interrupt. If SDSTL bit will be set in Set_Feature(), then Handle_EP_HALT() is completely needless (160 bytes!). STSTL bit may be ignored.
USB spec. p.207, 8.4.5 Handshake Packets:
"Once a function’s endpoint is halted, the function must continue returning STALL until the condition causing the halt has been cleared through host intervention."

3. Here's simpler implementation of Fifo_Read()/Fifo_Write(): yours 113/46 against my 60/50 bytes (76/66 bytes in reentrant version, but this should be needless). They correctly handle uNumBytes=0 (do almost nothing) as in original.


#pragma nooverlay
/*------------------------------------------------------------------------------
Read 'size' bytes from the endpoint FIFO given in 'addr'.
*/
static void Fifo_read(uint_fast8_t addr, uint_fast8_t size, Byte * dest)
{
while (USB0ADR & M_BUSY) {} // wait for USB0ADR ready
USB0ADR = M_BUSY | M_AUTORD | (addr & M_USBADDR); // set address and auto-read mode, initiate first read

{ // unload 'size' bytes from the selected FIFO
uint_fast8_t i;
for(i=0; i<size; i++)
{
while (USB0ADR & M_BUSY) {} // wait for USB0DAT ready
dest[i] = USB0DAT; // copy data byte
}
}

while (USB0ADR & M_BUSY) {} // wait for USB0ADR ready
USB0ADR = 0; // clear auto-read

return;
}

/*------------------------------------------------------------------------------
Write 'size' bytes to the endpoint FIFO given in 'addr'.
*/
static void Fifo_write(uint_fast8_t addr, uint_fast8_t size, Byte * dest)
{
while (USB0ADR & M_BUSY) {} // wait for USB0ADR ready
USB0ADR = (addr & M_USBADDR); // set address

{ // write 'size' to the selected FIFO
uint_fast8_t i;
for(i=0; i<size; i++)
{
while (USB0ADR & M_BUSY) {} // wait for USB0DAT ready
USB0DAT = dest[i];
}
}

return;
}

4. Maybe CMINT, IN1INT and OUT1INT register values should be AND-ed with CMIE, IN1IE, OUT1IE registers before storing in bCommon, bIn and bOut variables in Usb_ISR(), thus truly masking disabled interrupts? Never know when we fall again into this pitfall...

Regards,
Patryk

[This message has been edited by Patryk (edited September 06, 2006).]

IP: Logged

Patryk
Member
posted September 12, 2006 06:04 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
I see you're on forum now, Tsuneo, and I'm waiting for response :-)

IP: Logged

Tsuneo
Member
posted September 12, 2006 07:16 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Sorry, I was on a business trip these days. And I must go to another one tomorrow. I'll be back this week end.

"1. What for is second Delay() in Sysclk_Init()? No need according to datasheet.
Surely. It doesn't need. I'll revise it in the next version.

"2. Why SDSTL bit for EPs other than EP0 is set in Handle_EP_HALT() and not in Set_Feature()?"

The reason I put the Handle_EP_HALT into the SOF interrupt is that I'm not sure STSTL bit must always be cleared when it is set by the SIE. The original SiLabs code always resets it in the EP ISR. But I feel it may not be required. If so, the HALT handling is simplified as you said.
I'll check it and report it later.

HALT and STALL handling for bulk and interrupt EPs
a) HALT - must be supported in bulk and interrupt EPs
b) HALT - is set to one by
- Hardware (firmware) condition
- SetFeature(ENDPOINT_HALT)
c) HALT - is reset to zero by
- SetConfiguration(), SetInterface()
- ClearFeature(ENDPOINT_HALT)
d) STALL
- The host knows the EP in HALT when STALL is returned by the EP
- is always returned by the EP while the EP is in HALT

"3. Here's simpler implementation of Fifo_Read()/Fifo_Write()"
As of the Fifo_read, the problem is the autoread flag. It must be cleared before reading the last byte. Otherwise, reading last byte evokes an extra read. I found this problem when I wrote the ring buffer handler, where the Fifo_read is used contiguously.

When the whole FIFO data is unloaded by Fifo_Read in a single call, it doesn't matter even if the autoread flag is cleared after the last read.

"4. Maybe CMINT, IN1INT and OUT1INT register values should be AND-ed with CMIE, IN1IE, OUT1IE registers"
When we change the interrupt enable dynamically in the firmware, it is required. But when static, I think the revision of the dispatcher is enough.

Tsuneo

IP: Logged

egawtry
Member
posted September 13, 2006 12:08 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
I got the device working using a 342 (320s don't seem to work). There is one problem however. The serial port does not show up using the SetupDiGetClassDevs() function. Is it classed under another standard GUID? I would assume so since Device Manager sees it.

There doesn't seem to be a device class for it in Device Manager item details.

Anyone with an idea?

[This message has been edited by egawtry (edited September 13, 2006).]

IP: Logged

Patryk
Member
posted September 14, 2006 03:12 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
I believe using usbser.sys GUID will do, but I don't know content of that GUID. What GUID are you using for "normal" COM? serial.sys? serenum.sys?
About the lack of WM_DEVICECHANGE: maybe serenum.sys should be installed as upper filter? It is installed for normal COMs (above serial.sys) and for one of USB to UART converters (SiLabs, FTDI or Prolific, don't remember). Just a suggestion to Tsuneo, my knowledge of driver stack is very limited.

[This message has been edited by Patryk (edited September 14, 2006).]

IP: Logged

MAVO
New Member
posted September 14, 2006 05:47 AM     Click Here to See the Profile for MAVO   Click Here to Email MAVO     Edit/Delete Message
I have a couple of questions about this nice CDC implementation

1)
Is it possible to use it on Windows 98 (2nd or 1st edition)?

2)
You state that:
EscapeCommFunction( SETRTS ) and
EscapeCommFunction( CLRRTS ) does not work correctly in the usbser.sys, does this mean that the requests are never sent from the driver and therefore never captured in the firmware?

IP: Logged

egawtry
Member
posted September 14, 2006 12:22 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
By the usbser.sys GUID, do you mean the GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR as specified in the CDC_ACM.INF file? That only returns the hardware based serial ports. I also scan GUID_DEVINTERFACE_COMPORT which returns the Modems and most USB com ports (including the CP210x).

Hmmm... I wonder if I switch the GUID in the INF to COMPORT instead of SERENUM; if that would solve it? I will give that a shot.

-Erik

IP: Logged

Patryk
Member
posted September 15, 2006 04:28 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
The only GUID contained in CDC_ACM.INF is
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} - is that what you mean GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR?
I believe it differs from usbser.sys GUID, like with HID:
ClassGUID={745a17a0-74d3-11d0-b6fe-00a0c90f57da} in inf file
driver GUID (hidclass.sys? hidusb.sys?) {0x4D1E55B2, 0xF16F, 0x11CF, {0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}} - must be used for SetupDiGetClassDevs()
Switching ClassGUID in CDC_ACM.INF won't work: it describes Windows Setup class only, which is named Ports in previous line. I found somewhere in MSDN that ClassGUID is put in inf only to speed up device install.

IP: Logged

Tsuneo
Member
posted September 15, 2006 06:00 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Erik (egawtry),

I got the device working using a 342 (320s don't seem to work).

Do you use high-speed (HS) hub between the PC and the board? Then apply the latest (v1.4) version. I fixed HS hub problem for 'F32x on v1.4

Erik (egawtry) and Patryk,

As long as I disassembled usbser.sys, it doesn't register interface GUID to Windows system by IoRegisterDeviceInterface API. This API is usually used to register the interface GUID to the system in a device driver, which is compliant to the recent SetupDi- APIs. I don't know any other way to register the interface GUID from device driver.

The device manager list up devices using setup GUID. To retrieve device path using SetupDI- APIs, an interface GUID is required.
Maybe we must use the legacy symbolic path, like "\\\\.\\COMxx".

To find the COM number of the device, look up the registry. The same method described in AN197 is applicable.
"AN197: SERIAL COMMUNICATIONS GUIDE FOR THE CP210X" and AN197SW
7. Discovering CP210x COM Port

Patryk,

"About the lack of WM_DEVICECHANGE: maybe serenum.sys should be installed as upper filter?"

usbser.sys doesn't use serenum.sys as an upper filter. This is the output of DEVCON. It shows printer port, built-in modem, CP2102 and USB-CDC in this order. 'hhdserh' is the filter driver from the HHD serial monitor.

>devcon driverfiles =ports
ACPI„PNP0400„4&61F3B4B&0
Name: Driver installed from c:„windows„inf„msports.inf [LptPort]. 1 file(s) used by driver:
C:„WINDOWS„system32„DRIVERS„parport.sys
ACPI„PNP0501„4&61F3B4B&0
Name: Driver installed from c:„windows„inf„msports.inf [ComPort]. 2 file(s) used by driver:
C:„WINDOWS„system32„DRIVERS„serial.sys
C:„WINDOWS„system32„DRIVERS„serenum.sys
USB„VID_10C4&PID_EA60&MI_00„0001_00
Name: CP210x USB to UART Bridge Controller (COM4)
Driver installed from c:„windows„inf„oem79.inf [SLAB.Install]. 3 file(s) used by driver:
C:„WINDOWS„system32„DRIVERS„slabser.sys
C:„WINDOWS„system32„DRIVERS„slabcm.sys
C:„WINDOWS„system32„DRIVERS„slabcmnt.sys
USB„VID_16C0&PID_06EA„0001
Name: CDC ACM example device (COM5)
Driver installed from c:„windows„inf„oem81.inf [MYDEV000]. 1 file(s) used by driver:
C:„WINDOWS„system32„DRIVERS„usbser.sys
4 matching device(s) found.

>devcon stack =ports
ACPI„PNP0400„4&61F3B4B&0
Name: Setup Class: {4D36E978-E325-11CE-BFC1-08002BE10318} Ports
Class upper filters:
hhdserh
Controlling service:
Parport
ACPI„PNP0501„4&61F3B4B&0
Name: Setup Class: {4D36E978-E325-11CE-BFC1-08002BE10318} Ports
Class upper filters:
hhdserh
Upper filters:
NMFILTER
serenum
Controlling service:
Serial
USB„VID_10C4&PID_EA60&MI_00„0001_00
Name: CP210x USB to UART Bridge Controller (COM4)
Setup Class: {4D36E978-E325-11CE-BFC1-08002BE10318} Ports
Class upper filters:
hhdserh
Controlling service:
slabser
USB„VID_16C0&PID_06EA„0001
Name: CDC ACM example device (COM5)
Setup Class: {4D36E978-E325-11CE-BFC1-08002BE10318} Ports
Class upper filters:
hhdserh
Controlling service:
usbser
4 matching device(s) found.

Tsuneo

IP: Logged

Tsuneo
Member
posted September 15, 2006 06:21 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hello MAVO,
"Is it possible to use it on Windows 98 (2nd or 1st edition)?"

I checked it on only WinXP. I suppose it will work, bu not sure. It is said that behavior of usbser.sys has difference among Win98, 2K and XP. The result I wrote is from WinXP SP2.

For Win98/98SE/ME, Usbser.sys is downloaded from this web page
"WDM Modem and USB Modem Kits" from MSDN
http://www.microsoft.com/whdc/device/network/modem/WDMmodem.mspx

"2) You state that:
EscapeCommFunction( SETRTS ) and
EscapeCommFunction( CLRRTS ) does not work correctly in the usbser.sys, does this mean that the requests are never sent from the driver and therefore never captured in the firmware?"

Yes. usbser.sys doesn't issue any request when the host application executes these API. I checked it on a hardware bus analyzer.

Tsuneo

IP: Logged

Patryk
Member
posted September 15, 2006 06:27 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
usbser.sys doesn't use serenum.sys as an upper filter
When installed with CDC_ACM.INF - yes. But I feel that INF file decides if and which upper filters are installed for given device.

[This message has been edited by Patryk (edited September 15, 2006).]

IP: Logged

Patryk
Member
posted September 15, 2006 07:06 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
When the whole FIFO data is unloaded by Fifo_Read in a single call, it doesn't matter even if the autoread flag is cleared after the last read.
My implementation is based on HID_blinky example - it didn't care about clearing autoread flag before last read. But USB_INT example cares! As Fifo_Read() read always whole FIFO in both examples, that doesn't matter. I also found extra read problem when implementing interrupts for EP2 IN/OUT, but there was completely specialized read routine.

Anyway I end up with your implementation (I like order, and that DJNZ in loop I cannot achieve using indexing instead pointer) improving Fifo_Read() a little to 100bytes instead of 117 under SDCC 2.6.0.


void Fifo_read(TFByte addr, TFByte size, TByte * dest)
{
if (size != 0) // check if >0 bytes requested to avoid read
{
while (USB0ADR & M_BUSY) {} // wait for BUSY->'0' (data ready)
// assert((addr & M_USBADDR) == 0);
addr &= M_USBADDR;
if (size == 1)
// set address and initiate (last) read
USB0ADR = M_BUSY | addr;
else
{ // unload 'size'-1 bytes from the selected FIFO
USB0ADR = M_BUSY | M_AUTORD | addr; // set address and auto-read mode, initiate first read
do
{
while (USB0ADR & M_BUSY) {} // wait for BUSY->'0' (data ready)
*dest = USB0DAT; // copy data byte
dest++;
} while (--size != 0);
USB0ADR = 0; // clear auto-read before last read
}
// last read
while (USB0ADR & M_BUSY) {} // wait for BUSY->'0' (data ready)
*dest = USB0DAT; // copy data byte
}
return;
} // Fifo_read()

In Fifo_Write() loop I wait for BUSY before write. Although it is dummy wait in first loop, but we exit that loop sooner on last write.

[This message has been edited by Patryk (edited September 15, 2006).]

IP: Logged

egawtry
Member
posted September 15, 2006 11:21 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Since the SERENUM was predefined for the INF device class, it needs to be installed that way. A bit screwy if you ask me.

Tsuneo,
Using the registry is great if you have a dedicated app, but what about legacy apps from 3rd parties?

Does anyone have any idea how Device Manager gets the list of ports? Maybe I should enum all devices and parse out the COM ports. I will try that next.

-Erik

IP: Logged

Tsuneo
Member
posted September 16, 2006 05:11 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Patryk and Erik,

Serial modems usually use serenum.sys as a filter driver for serial.sys, as shown in DEVCON output in my previous post. As the source code of serenum.sys and serial.sys are provided in WinDDK, I read them through. As the result, serenum.sys seems to be promising.

a) SetupDi-API compatibility by serenum.sys
Serenum.sys seems to work to fit usual serial devices to SetupDi-API.
Serenum.sys registers GUID_SERENUM_BUS_ENUMERATOR as an interface GUID. Therefore, this GUID is available to detect USB-CDC device by SetupDi-API, when serenum.sys is attached to usbser.sys as a filter driver.
Using SetupDiGetDeviceRegistryProperty( SPDRP_HARDWAREID ), the hardware ID of the device is retrieved. As the hardware ID for USB-CDC devices is "USB\Vid_vvvv&PID_pppp&Rev_rrrr", this ID distinguishes USB-CDC from other devices using serenum.sys.
Also SetupDiGetDeviceRegistryProperty( SPDRP_FRIENDLYNAME ) gives a short description including COM port number, such as "CDC ACM example device (COMxx)" as we can see in the Device Manager window.

Serial.sys correctly registers GUID_CLASS_COMPORT as described in "Plug and Play external COM Device Specification" from MS. However, usbser.sys doesn't register this GUID. In this point, usbser.sys is weird too.

b) WM_DEVICECHANGE compatibility
Serenum.sys supports the PnP event, IRP_MN_QUERY_DEVICE_RELATIONS( BusRelations ) correctly. When serenum.sys detects device arrival or removal, it issues IoInvalidateDeviceRelations() and triggers IRP_MN_SURPRISE_REMOVAL.

Though it isn't clear whether WM_DEVICECHANGE is enabled by serenum.sys without any registration or not, we can register the device notification with GUID_SERENUM_BUS_ENUMERATOR at least, and it'll return DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE.

c) Device detection
Serenum.sys detects devices according to "COM Enumerator Detection" section of above MS COM spec. So, the device must respond the sequence defined in this spec correctly. The modem implementation described in this spec seems to fit to USB-CDC better.

OK, as the next step, I'll examine INF file modification to attach serenum.sys.

Tsuneo

IP: Logged

Patryk
Member
posted September 21, 2006 08:36 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
USB_ISR.c, line 241:
if ( (!(ControlReg & rbSUEND)) || (!(ControlReg & rbOPRDY)) ) // Check to see if Setup End or Out Packet received, if so
// do not put any new data on FIFO

Shouldn't there be '&&' in place of '||' according to comment?
What is purpose of this check? SUEND may rise right after this check and we will "put new data on FIFO" anyway.

IP: Logged

Tsuneo
Member
posted September 21, 2006 12:24 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Yes, it must be '&&'.

There is still a little possibility to come across SUEND here.
At the end of the SETUP stage handler ('if' clause of Ep_Status0 == EP_IDLE), the EP0 OUT FIFO becomes open by SOPRDY. Thereafter, EP0 has a chance to receive early SETUP. As Ep_Status0 is set to EP_TX in this SETUP stage handler, the code flow enters to this section contiguously after the SETUP stage handler.

Umm.. I examined most of SiLabs code, but missed it. Thanks.

Tsuneo

IP: Logged

Patryk
Member
posted September 22, 2006 08:22 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
I still cannot fully understand that SiLabs SIE implementation. Terminology in datasheet seems to differ from USB spec. For example F320 datasheet p. 161:

15.10.Endpoint0
...
An Endpoint0 interrupt is generated when:
1.A data packet (OUT or SETUP) has been received and loaded into the Endpoint0 FIFO. The OPRDY bit (E0CSR.0) is set to ‘1’ by hardware.
2.An IN data packet has successfully been unloaded from the Endpoint0 FIFO and transmitted to the host; INPRDY is reset to ‘0’ by hardware.
3.An IN transaction is completed (this interrupt generated during the status stage of the transaction).

Should point #3 be:
a.) An IN transaction is completed (this interrupt generated during the handshake phase of the transaction).
or
b.) An IN transfer is completed (this interrupt generated during the status stage of the transfer).

Below is what I (after USB spec) mean by transfer, transaction, stage, phase etc. by example of, say, GET_DESCRIPTOR request.


-> host to device
<- device to host

Control transfer
setup stage (1 transaction)
-> token phase - SETUP token packet
-> data phase - DATA0 data packet
<- handshake phase - ACK handshake packet
data stage (0-n transactions)
1st data transaction
-> token phase - IN token packet
<- data phase - DATA1 data packet
-> handshake phase - ACK handshake packet
2nd data transaction
-> token phase - IN token packet
<- data phase - DATA0 data packet
-> handshake phase - ACK handshake packet
.
.
.
n-th (last) data transaction
-> token phase - IN token packet
<- data phase - DATA0 or DATA1 data packet
-> handshake phase - ACK handshake packet
status stage (1 transaction)
-> token phase - OUT token packet
-> data phase - DATA1 data packet
<- handshake phase - ACK handshake packet

Can you help, Tsuneo, with some state diagram or more detailed explanation about EP0? I need to verify that firmware in every detail, it look somewhat flawed to me. Consider my second question ("What is purpose of this check? SUEND may rise right after this check and we will "put new data on FIFO" anyway.")

Regards,
Patryk

IP: Logged

egawtry
Member
posted September 22, 2006 12:31 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
A fix for the INF so enumeration works:

CDC_ACM.inf

This will make Windows enumerate the COM port normally.

Tsuneo, maybe you want to put this into the zip file?

-Erik

[This message has been edited by egawtry (edited September 22, 2006).]

IP: Logged

Tsuneo
Member
posted September 22, 2006 07:20 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Patryk,

Please see "Figure 3-5" of AN139 (AN139 rev1.3 p10)

"1.A data packet (OUT or SETUP) has been received and loaded into the Endpoint0 FIFO..."
This sentence corresponds the interrupt at the end of 1-1) setup stage of Fig.3,4.5, and 1-2) each OUT transaction in Data stage of Fig.3.

"2.An IN data packet has successfully been unloaded from the Endpoint0 FIFO and transmitted to the host;..."
This sentence matches to the interrupt at the end of each IN transaction in Data stage of Fig.4

"3.An IN transaction is completed (this interrupt generated during the status stage of the transaction)."
This sentence should match to the remaining interrupts, ie. the interrupt of the end of status stage of Fig.3,4,5. Therefore, it must be something like,
"3.An IN or OUT transaction is completed as the status stage of a control transfer"

Tsuneo

IP: Logged

Tsuneo
Member
posted September 22, 2006 07:22 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Thank you Erik,

I'll include your INF file to the zip file in the next update.
As serenum.sys requires "COM Enumerator Detection", the body of CDC code is needed a small modification also. I'll assign another VID/PID to this configuration, to avoid a mess on installation of the device drivers.

Tsuneo

IP: Logged

Tsuneo
Member
posted September 24, 2006 02:17 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Patryk,
"What is purpose of this check?
SUEND may rise right after this check and we will "put new data on FIFO" anyway."

I also feel this part of the implementation a little dirty.
This is supposed Control read (IN) transfer sequence.
host        SIE             firmware
SETUP --> EP_IDLE SETUP stage
DATA0 -->
<-- ACK --> OPRDY
+ interrupt SETUP stage handler
EP_TX
<-- SOPRDY
__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..
IN --> IN data stage handler DATA stage
<-- NAK fill EP0 IN FIFO
<-- INPRDY '1'
return from interrupt
IN -->
<-- DATA1
ACK --> --> INPRDY '0'
+ interrupt fill EP0 IN FIFO
<-- INPRDY '1'
return from interrupt
...
...
IN -->
<-- DATA0
ACK --> --> INPRDY '0'
+ interrupt fill EP0 IN FIFO
<-- INPRDY '1' (last data)
+ DATAEND EP_IDLE
return from interrupt
IN -->
<-- DATA1
ACK --> --> INPRDY '0'
+ interrupt
return from interrupt
__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..
OUT --> STATUS stage
DATA1 -->
<-- ACK --> interrupt


Maybe you are worring about this sequence.
Premature SETUP

host        SIE             firmware
SETUP --> EP_IDLE
DATA0 -->
<-- ACK --> OPRDY
+ interrupt SETUP stage handler
EP_TX
<-- SOPRDY
__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..__..
IN data stage handler
fill EP0 IN FIFO
<-- INPRDY '1'
return from interrupt
SETUP -->
DATA0 -->
<-- ACK --> SUEND
+ OPRDY
+ interrupt
<-- SSUEND EP_IDLE

In this case, the IN FIFO is cleared by SUEND as long as INPRDY is set to '1' by the firmware before the premature SETUP arrives.
INPRDY: IN Packet Ready (C8051F32x.pdf rev1.1 p164)
Software should write ‘1’ to this bit after loading a data packet into the Endpoint0 FIFO for
transmit. Hardware clears this bit and generates an interrupt under either of the following
conditions:
1. The packet is transmitted.
2. The packet is overwritten by an incoming SETUP packet.
3. The packet is overwritten by an incoming OUT packet.

However, when premature SETUP arrives before the firmware sets INPRDY, the IN FIFO isn't cleared. This is the point you are talking about.

Premature SETUP is issued by host as an error recovery.
This malignant sequence occurs when only the ACK to the first SETUP/DATA0 is broken by noise, while SETUP/DATA0 are intact. The probability is very rare, but surely, it is not zero.

Tsuneo

[This message has been edited by Tsuneo (edited September 24, 2006).]

IP: Logged

Patryk
Member
posted September 25, 2006 06:21 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
Tsuneo: you always got some spare helping hand :-) (here AN139). I thought I read all SiLabs USB application notes, and now I see it is only partially truth: all from Applications page :-| Why this one isn't listed there (only on USB Products page) is a sweet secret of SiLabs :-) I'm beginning to read it in hope it answers some questions. Thanks!

[This message has been edited by Patryk (edited September 25, 2006).]

IP: Logged

mmk
New Member
posted October 03, 2006 10:38 AM     Click Here to See the Profile for mmk     Edit/Delete Message
Hi,

Can anyboday provide some help: Is there a way to get a USB device to enumerate as more than one virtual com port using the CDC? If yes what are the steps to do so?
I'm not very familiar with Windows drivers / classes, any pointers to learn some basics?

Thanks!!!

IP: Logged

Tsuneo
Member
posted October 03, 2006 11:10 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hello mmk,
"Is there a way to get a USB device to enumerate as more than one virtual com port using the CDC? If yes what are the steps to do so?"

Short answer - It cannot.
Long answer - The Windows built-in driver, usbser.sys, doesn't accept multiple port configuration. Many people (including me ) has attacked it, but no one succeeds.
"CDC device with multiple serial port" from USB.org

Surely, when you manage to write a custom device driver instead of usbser.sys, it can. But, it isn't realistic.

Find an existing product, such as,
http://www.ftdichip.com/Products/FT2232C.htm

Do you actually need COM port? You can assign 'direct' USB ports as many as the number of endpoints on the device.

Tsuneo

IP: Logged

egawtry
Member
posted January 05, 2007 02:18 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
My Micro crashes every time Update_Line_State() is called. Any ideas?

Also: You need to disable interrupts while reading or writing to the FIFOs, otherwise they overrun.

// TX buffer (host --> UART), UART side
BYTE COMGetByte( void )
{
BYTE dt;

if( TXcount == 0 )
{
TXReady = 0;
return 0xFF;
}

EIE1 &= ~0x02; // disable USB interrupt

dt = *TXRDPtr;
if ( TXRDPtr == (TXBuffer + (TXBUFSIZE - 1)) ) // at the end of the buffer
TXRDPtr = TXBuffer; // go to the head of the buffer
else
TXRDPtr++;

TXcount--;
TXReady = (TXcount > 0);

EIE1 |= 0x02; // enable USB interrupt

return dt;
}

// RX buffer (UART --> host), UART side
void COMPutByte( BYTE dt )
{
if( RXcount >= RXBUFSIZE )
{
RXReady = 0;
return;
}

EIE1 &= ~0x02; // disable USB interrupt

*RXWTPtr = dt;
if ( RXWTPtr == (RXBuffer + (RXBUFSIZE - 1)) ) // at the end of the buffer
RXWTPtr = RXBuffer; // go to the head of the buffer
else
RXWTPtr++;

RXcount++;
RXReady = (RXcount < RXBUFSIZE);

EIE1 |= 0x02; // enable USB interrupt

}

[This message has been edited by egawtry (edited January 05, 2007).]

IP: Logged

Tsuneo
Member
posted January 05, 2007 07:26 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"My Micro crashes every time Update_Line_State() is called. Any ideas?"

Oops, sorry it's a bug.


USB_CDC_UART.c
void Update_Line_State( BYTE st )
{
EIE1 &= ~0x02; // disable USB interrupt
cs_Line_State = st;
cs_Line_State_Update = TRUE;
// EIE1 |= ~0x02; // enable USB interrupt <---- bug
EIE1 |= 0x02; // enable USB interrupt
}

"Also: You need to disable interrupts while reading or writing to the FIFOs, otherwise they overrun."

I don't think so.
COMGetByte() and COMPutByte() doesn't handle any parameter of the USB engine, and the pair subroutines of these routines, Handle_In2() and Handle_Out2() in USB_Class_Requests.c, are also executed in main loop. USB interrupt is disabled in Handle_In2() and Handle_Out2(). Therefore, any parameter of the ring buffers doesn't concern to USB interrupt.

Rather, when COMGetByte() and COMPutByte() are used in another interrupt such as UART, Handle_In2() and Handle_Out2() must be modified to disable this interrupt, as follows.
Copied from "Silabs USB Bulk drvrs updated to handle EP0 data packet after cmd packet."
posted December 19, 2006 07:41 AM by Tsuneo


void Handle_In2( void )
{
BYTE ControlReg;
BYTE send_cnt, first_cnt, second_cnt;
UINT pos;
bit turnover;

UINT RXcount_hold;
bit ES0_hold;

if (Ep_StatusIN2 == EP_IDLE) // If endpoint is currently halted,
{
EIE1 &= ~0x02; // disable USB interrupt

POLL_WRITE_BYTE(INDEX, 2); // Set index to endpoint 2 registers
POLL_READ_BYTE(EINCSR1, ControlReg); // Read contol register for EP

ES0_hold = ES0; // disable UART0 interrupt
ES0 = 0; // around RXcount access
RXcount_hold = RXcount;
ES0 = ES0_hold;

// RX buffer (UART --> host), USB side
// FIFO is empty and must send?
if ( !(ControlReg & rbInINPRDY) && RXcount_hold )
{
// determine the bytes to send in this transaction
if ( RXcount_hold > EP2_PACKET_SIZE )
send_cnt = EP2_PACKET_SIZE;
else
send_cnt = (BYTE)RXcount_hold;

pos = RXBUFSIZE - (RXRDPtr - RXBuffer); // consider on wrap around of ring buffer
if ( send_cnt < pos )
{
first_cnt = send_cnt;
second_cnt = 0;
turnover = FALSE;
}
else
{
first_cnt = (BYTE)pos;
second_cnt = send_cnt - first_cnt;
turnover = TRUE;
}

FIFO_WRITE_FUNC( FIFO_EP2, first_cnt, RXRDPtr ); // send bytes to FIFO
if ( second_cnt != 0 )
FIFO_WRITE_FUNC( FIFO_EP2, second_cnt, RXBuffer );
POLL_WRITE_BYTE(EINCSR1, rbInINPRDY);

if ( turnover )
RXRDPtr = RXBuffer + second_cnt;
else
RXRDPtr += send_cnt;

ES0_hold = ES0; // disable UART0 interrupt
ES0 = 0; // around RXcount access
RXcount -= send_cnt;
RXReady = (RXcount != RXBUFSIZE);
ES0 = ES0_hold;

}

EIE1 |= 0x02; // enable USB interrupt
}
}

Tsuneo

[This message has been edited by Tsuneo (edited January 05, 2007).]

IP: Logged

egawtry
Member
posted January 08, 2007 12:35 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
With that I have successfully implemented a direct transfer to the 342's UART, thus replacing the CP210x with a chip with flexibility and doesn't need the drivers. I have tested it at 2400 to 115200 baud without any glitches - I would test it faster but my hardware COM port on the PC won't go any faster.

Does anyone know why SiLabs didn't use this method on the CP210x? It seems to be MUCH better since it uses the built in serial port driver. I wonder if it would work on Linux or a Mac without additional drivers?

-Erik

[This message has been edited by egawtry (edited January 08, 2007).]

IP: Logged

Tsuneo
Member
posted January 08, 2007 06:32 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"Does anyone know why SiLabs didn't use this method on the CP210x?"

a) Windows built-in device driver, usbser.sys, had many bugs and defects on its feature in the early OS version.
These bugs have been fixed in the recent WinXP version, but the early versions are left unfixed.

Therefore, the manufacturers of USB-UART chips should provide their original device drivers
to ensure stable connection in every OS version.

b) The USB CDC spec doesn't support CTS handshake line.


"I wonder if it would work on Linux or a Mac without additional drivers?"

Yes, Linux and MacOSX have built-in device driver for CDC ACM.

This Atmel appnote suggests how to use CDC ACM devices in various OS.

"USB to Serial Adapter" from Atmel
http://www.atmel.com/dyn/resources/prod_documents/doc5693.pdf

Tsuneo

[This message has been edited by Tsuneo (edited January 08, 2007).]

IP: Logged

egawtry
Member
posted February 02, 2007 10:55 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Anyone know how to get CDC working with Vista? The usbser.sys and serenum.sys exist, but the INF crashes when I try to use it.

Part of it may be that there is no layout.inf. I tried figuring it out from MS documentation, but all they talk about is a cell phone version of CDC that doesn't work anyway.

-Erik

IP: Logged

Tsuneo
Member
posted February 02, 2007 01:14 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Erik,

Maybe "include=mdmcpq.inf" is the key, but I didn't try it.

"How to use or to reference the Usbser.sys driver from universal serial bus (USB) modem .inf files" from MSDN
http://support.microsoft.com/kb/837637/en-us

Tsuneo

[This message has been edited by Tsuneo (edited February 02, 2007).]

IP: Logged

egawtry
Member
posted February 10, 2007 01:55 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
That did the trick. It is bad that we need a separate INF for Vista. MS messed up there.

Right now it is the only USB serial port that I can find that actually works with Vista.

-Erik

IP: Logged

grantb4
New Member
posted April 03, 2007 06:52 PM     Click Here to See the Profile for grantb4     Edit/Delete Message
Hi,

Can someone please summarize shortcomings, problems, bugs in using this CDC implementation? I'm not so much referring to the Tseneo's code, but more on Microsoft's end (usbser.sys, etc). In other word, if one were to implement a device as well as possible, what problems would remain? It sounds like one limitation may be that you can only have one such device plugged into the PC. Is this correct? Does this same problem occur on Linux? Any other things like this?

Thanks,
GB

IP: Logged

thyagaraj
New Member
posted April 05, 2007 12:56 AM     Click Here to See the Profile for thyagaraj   Click Here to Email thyagaraj     Edit/Delete Message
Hello Tsuneo,
The USB_UART_CDC code was really very useful for one of our USB to UART solution using the F321.
Please let me know the changes that are to be done in the code for UART to USB conversion.That is, I would like to convert the UART data(from a different PC) to USB(of my PC) and receive it on the Hyperterminal.

IP: Logged

Tsuneo
Member
posted April 05, 2007 04:04 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
thyagaraj,

Isn't it better to apply an existing USB-to-UART chips like SiLabs CP210x for simple VCP application?
You don't need to hustle to code it, and it's low-cost.

This VCP implementation works when you extend the function of the USB-to-UART chips.
a) Connecting other peripherals than UART
- VCP to parallel port, I2C, SPI, ADC...

b) 'Smart' converter
- local spooler
- COM port switcher (1:N COM port connection)
- code conversion
etc.

Tsuneo

IP: Logged

frief
Member
posted May 29, 2007 08:05 AM     Click Here to See the Profile for frief     Edit/Delete Message
Hello

and thanks Tsuneo for your USB CDC implementation!)
And I should have contributed to this thread: http://www.cygnal.org/ubb/Forum1/HTML/002146.html
as well... Again: thanks a lot.

I've a question about the CTS handshake handling in USB_Main.c line 196:


if ( Switch1State ) line_state |= CDC_DSR;
if ( Switch2State ) line_state |= CDC_CTS;
Update_Line_State( line_state );

CDC_CTS is defined as 0x80 which would according to usbcdc11.pdf table 69 be "reserved (future use)". Is CDC_DCD meant there?

Greetings,
Frieder

IP: Logged

Tsuneo
Member
posted May 29, 2007 10:18 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Yes, as you pointed out, the CDC spec (usbcdc11.pdf) lacks CTS signal handling.
This implementation of CTS is good just for MacOS X.
It doesn't work for Windows and Linux.

Tsuneo

IP: Logged

sbj
New Member
posted June 12, 2007 12:10 PM     Click Here to See the Profile for sbj     Edit/Delete Message
I'm trying to get the implementation to work for F326. I'm using hyperterminal and can't seem to get the data to transfer to the board. Any ideas?

IP: Logged

Tsuneo
Member
posted June 12, 2007 06:15 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi sbj,

"I'm trying to get the implementation to work for F326."

Visit this topic, "VCP on F326"

Tsuneo

IP: Logged

thyagaraj
New Member
posted July 05, 2007 05:02 AM     Click Here to See the Profile for thyagaraj   Click Here to Email thyagaraj     Edit/Delete Message
Hello Tsuneo,

We have modified the CDC skeleton for a USB to UART conversion code.The code is working fine except for one problem.The UART to USB conversion works fine for any baud rate.
In case of USB to UART conversion,the changes made to the baud rate on the hyperterminal makes no difference in speed.The conversion happens only at 9600bps regardless of the baud rate set.

What could be wrong

IP: Logged

All times are CT (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | MCU User Forum

Have you seen our MCU Knowledge Base?


Ultimate Bulletin Board 5.47b

Site Guide Privacy Legal