How might I implement RTS / CTS handshaking using the dual VCom example (AN10420) for the LPC2148? I have an audio stream on VCOM0 I would like to halt if my input buffer is almost full and continue transfer once it has enough space again. I am only interested in data from the virtual port (NO_UART_CABLE = 1), not sending it to the LPC2148's physical UART.
I thought perhaps I could set the modem0status bits (below) defined in the example to control the CTS line, with bit allocations matching the 16550 uart spec (bit 4 of modem status register = CTS) but transfer from the host side doesn't stop. In the physical implementation, SetSIORTS() controls the LPC2148's UART registers to assert the RTS state, but I don't see how the host driver can detect that the device UART's CTS pin is asserted.
Thanks for any help.
// EP3 is used to report UART0 status, and EP9 //is used to report UART1 status respectively if ( ReportStatus0 ) { ReportStatus0 = 0; // For Interrupt IN on EP3 USB_WriteEP( 3 | 0x80, &Modem0Status, sizeof(Modem0Status) ); } if ( ReportStatus1 ) { ReportStatus1 = 0; // For Interrupt IN on EP9 USB_WriteEP( 9 | 0x80, &Modem1Status, sizeof(Modem1Status) ); }
See the endpoint descriptors on USB_ConfigDescriptor[] (usbdesc.c). Unfortunately, EP3 and EP9 is not used on this example.
Moreover, though the interrupt IN EPs (EP1 and EP4) are defined in the descriptor, these EPs are not written in anywhere. Search "USB_WriteEP" in the source code globally. You cannot find these code. USB_WriteEP(0x80 | 0x01, ...) USB_WriteEP(0x80 | 0x04, ...)
That is, no handshake lines of input (CTS, DSR, DCD) are sent to PC. However, the device driver surely expects the interrupt pipe as ModemStatus.
usbio.c StartInterruptUrb( ... ) { ... // Initialize the URB we use for reading the interrupt pipe UsbBuildInterruptOrBulkTransferRequest( urb, sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER), PipeHandle, &Extension->intdata, NULL, 4, USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, NULL); OnInterrupt( ... ) { if (Extension->DeviceIsOpened == TRUE && (Extension->intdata[2] == 0x60)) { SerialHandleModemUpdate( Extension, ... ); modmflow.c SerialHandleModemUpdate( ... ) { ModemStatus = Extension->intdata[3];
As of the flow control, this example implements nothing. The device driver sends vendor request to the device, expecting the device handles flow control. However, the device ignores the request in SetSIOFlowControl().
1) Flow control 1-1) Host app SetCommState DCB.fRtsControl = RTS_CONTROL_HANDSHAKE (0x02) 1-2) Device driver usbcom.h #define VendorFlowCtrl 0x07 ioctl.c UsbCom_ProcessIOCTL( ... ) { ... switch (ioControlCode) { ... case IOCTL_SERIAL_SET_HANDFLOW: { USHORT Value = 0; ... if (HandFlow->FlowReplace & SERIAL_RTS_HANDSHAKE) Value |= 0x11; ... UsbCom_SendVendor(DeviceObject, VendorFlowCtrl, Value); 1-3) Vendor request bRequest = VendorFlowCtrl (0x07) wValue = Value (0x11) 1-4) firmware usbcore.c void USB_EndPoint0 (DWORD event) { ... case REQUEST_VENDOR: #if USB_VCOM UARTSettingCmd = SetupPacket.bRequest & 0xFF; UARTSettingData = SetupPacket.wValue.WB.L; if (!VCOM_SetSIOSetup( UARTSettingCmd, UARTSettingData )) { goto stall_i; } USB_DataInStage(); #endif break; vcomuser.h #define FLOWCTRL_SETUP 0x07 vcomuser.c BOOL VCOM_SetSIOSetup( BYTE Cmd, BYTE Data ) { case FLOWCTRL_SETUP: SetSIOFlowControl( ChannelNum, Data ); void SetSIOFlowControl( BYTE channelNum, BYTE ConfigValue ) { /* NO flow control setting is neceaasry, unlike the UART on x51 */ if ( channelNum == 0 ) { ConfigValue = ConfigValue; } else if ( channelNum == 1 ) { ConfigValue = ConfigValue; } }
Therefore, you have to implement the flow control by yourself from scratch. Don't worry. It's very easy.
To halt the bulk OUT transfer, don't call DeviceData2UART() in USB_EndPoint2() Instead, raise a flag, Host2Data0, like Data2Host0.
vcomuser.c BYTE Host2Data0 = 0; void USB_EndPoint2 (DWORD event) { switch (event) { case USB_EVT_IN: Data2Host0 = 1; break; case USB_EVT_OUT: // DeviceData2UART( 0 ); // <--------- comment out Host2Data0 = 1; break; } event; }
In the main loop, poll this Host2Data0. When Host2Data0 is asserted, AND there is enough room on the buffer, drop Host2Data0 and call DeviceData2UART(),
That's all.
While the endpoint FIFO is not empty, the OUT EP returns NAK to the host. When the host sees NAK, it retries the transaction until the EP accepts it. No data drops. That is, host waits for the firmware to unload the data from the FIFO. Therefore, the flow control is done on the USB protocol.
Tsueno