 RE: USB CDC-ACM function class Tsuneo Chinzei Keil CDC example misses these points on bulk endpoints (EPs) handling for CDC. a) bulk OUT EP The transfer speed is automatically tuned using NAK flow control. While the EP is occupied by current received data, the transfer from host is delayed by NAKing. In this way, lossless transfer is achieved. When the data is left unread on the EP buffer, no more EP interrupt is generated. Then, we have to poll the endpoint status periodically out side of the EP ISR, too. SOF interrupt is often used for this purpose. A typical implementation is, In USB_SOF_Event() (usb_user.c) [b]AND[/b] USB_EndPoint2() ISR - USB_EVT_OUT selector, call this subroutine. - Select the bulk OUT EP (USB_CTRL) - Check PKT_RDY bit of RX_PLENGTH - - if not ready, return - Compare the packet length and the room on the RX buffer of your firmware - - if no room, return - Read out data from the EP to the RX buffer - Clear the EP (CMD_SEL_EP and CMD_CLR_BUF) This subroutine is easily made modifying USB_ReadEP() (usbhw.c) Just add 2-3 lines. b) bulk IN EP Here, NAK flow control is applied, too. Just when we have data to send, the data is put to the bulk IN EP. When no data is written to the IN EP, no more EP interrupt is generated. Then, we have to poll the number of data on the TX buffer periodically out side of the EP ISR, too. SOF interrupt is often used for this purpose. When the last transaction is just 64 bytes, host controller waits for next short packets forever. Until receiving a shot packet, host controller doesn't pass the data to the input buffer on the PC device driver. In this case, Zero-Length Packet (ZLP) should be put to IN EP, to speed up the response of host. This ZLP is also added in SOF ISR. A typical implementation is, In USB_EndPoint2() - always sends full (64 bytes) packet USB_EndPoint2() ISR - USB_EVT_IN selector - If the number of the data on the TX buffer is less than 64, return - Check the FE bit of "Select Endpoint" command, if no empty EP buffer, return - - WrCmd( CMD_SEL_EP(EPAdr(EPNum)) ); if ( CMD_DATA & EP_SEL_F != 0 ) return; - Send 64 bytes from the buffer to the IN EP using USB_WriteEP() - Raise a flag - flag_send_ZLP In USB_SOF_Event(), call this subroutine - Check the FE bit of "Select Endpoint" command, if no empty EP buffer, return - send_cnt = number of data on the TX buffer - if (send_cnt == 0) && (! flag_send_ZLP), return - if send_cnt >= 64 bytes, send_cnt = 63 bytes (short packet) - Send specified number of data, USB_WriteEP( CDC_DEP_IN, TX_buffer, send_cnt ); - drop flag_send_ZLP For TX and RX buffer, cyclic buffers fit well for this implementation.
"Could someone provide me with an feasable example of how to achieve this?
Implement above modification by yourself for your exercise :-) Or wait until KEIL brush up the implementation. Tsuneo |