micropython/ports/stm32/usbd_cdc_interface.h
Andrew Leech e4fcd216e0 stm32/usbd_cdc_interface: Remove full==size-1 limitation on tx ringbuf.
Before this commit the USB VCP TX ring-buffer used the basic implementation
where it can only be filled to a maximum of buffer size-1.  For a 1024 size
buffer this means the largest packet that can be sent is 1023.  Once a
packet of this size is sent the next byte copied in goes to the final byte
in the buffer, so must be sent as a 1 byte packet before the read pointer
can be wrapped around to the beginning.  So in large streaming transfers,
watching the USB sniffer you basically get alternating 1023 byte packets
then 1 byte packets.

This commit changes the ring-buffer implementation to a scheme that doesn't
have the full-size limitation, and the USB VCP driver can now achieve a
constant stream of full-sized packets.  This scheme introduces a
restriction on the size of the buffer: it must be a power of 2, and the
maximum size is half of the size of the index (in this case the index is
16-bit, so the maximum size would be 32767 bytes rounded to 16384 for a
power-of-2).  But this is not a big limitation because the size of the
ring-buffer prior to this commit was restricted to powers of 2 because it
was using a mask-based method to wrap the indices.

For an explanation of the new scheme see
https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/

The RX buffer could likely do with a similar change, though as it's not
read from in chunks like the TX buffer it doesn't present the same issue,
all that's lost is one byte capacity of the buffer.

USB VCP TX throughput is improved by this change, potentially doubling the
speed in certain cases.
2020-06-29 17:21:37 +10:00

87 lines
3.7 KiB
C

/*
* This file is part of the MicroPython project, http://micropython.org/
*/
#ifndef MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H
#define MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H
/**
******************************************************************************
* @file USB_Device/CDC_Standalone/Inc/usbd_cdc_interface.h
* @author MCD Application Team
* @version V1.0.1
* @date 26-February-2014
* @brief Header for usbd_cdc_interface.c file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
#ifndef USBD_CDC_RX_DATA_SIZE
#define USBD_CDC_RX_DATA_SIZE (1024) // this must be 2 or greater, and a power of 2
#endif
#ifndef USBD_CDC_TX_DATA_SIZE
#define USBD_CDC_TX_DATA_SIZE (1024) // This must be a power of 2 and no greater than 16384
#endif
// Values for connect_state
#define USBD_CDC_CONNECT_STATE_DISCONNECTED (0)
#define USBD_CDC_CONNECT_STATE_CONNECTING (1)
#define USBD_CDC_CONNECT_STATE_CONNECTED (2)
// Flow control settings
#define USBD_CDC_FLOWCONTROL_NONE (0)
#define USBD_CDC_FLOWCONTROL_RTS (1)
#define USBD_CDC_FLOWCONTROL_CTS (2)
typedef struct _usbd_cdc_itf_t {
usbd_cdc_state_t base; // state for the base CDC layer
uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer
uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it
volatile uint16_t rx_buf_put; // circular buffer index
uint16_t rx_buf_get; // circular buffer index
uint8_t rx_buf_full; // rx from host will be blocked while this is true
uint8_t tx_buf[USBD_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
uint16_t tx_buf_ptr_in; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when new data is available
volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when data is drained
uint16_t tx_buf_ptr_out_next; // next position of above once transmission finished
uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
volatile uint8_t connect_state; // indicates if we are connected
uint8_t attached_to_repl; // indicates if interface is connected to REPL
uint8_t flow; // USBD_CDC_FLOWCONTROL_* setting flags
} usbd_cdc_itf_t;
// This is implemented in usb.c
usbd_cdc_itf_t *usb_vcp_get(int idx);
static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) {
return cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTED;
}
int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc);
int usbd_cdc_tx_flow(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len);
int usbd_cdc_tx(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len, uint32_t timeout);
void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len);
int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc);
int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout);
#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H