USB: increase transmit buffer and simplify locking mechanism
This commit is contained in:
parent
22932d0135
commit
721e181f15
|
@ -20,26 +20,35 @@
|
|||
|
||||
/* standard libraries */
|
||||
#include <stdint.h> // standard integer types
|
||||
#include <stdio.h> // standard I/O facilities
|
||||
#include <stdlib.h> // general utilities
|
||||
|
||||
/* STM32 (including CM3) libraries */
|
||||
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
||||
#include <libopencm3/cm3/scb.h> // reset utilities
|
||||
#include <libopencm3/cm3/nvic.h> // interrupt handler
|
||||
#include <libopencm3/cm3/sync.h> // synchronisation utilities
|
||||
#include <libopencm3/stm32/rcc.h> // real-time control clock library
|
||||
#include <libopencm3/stm32/gpio.h> // general purpose input output library
|
||||
#include <libopencm3/usb/usbd.h> // USB library
|
||||
#include <libopencm3/usb/cdc.h> // USB CDC library
|
||||
#include <libopencm3/usb/dfu.h> // DFU definitions
|
||||
|
||||
/* own libraries */
|
||||
#include "global.h" // global utilities
|
||||
#include "usb_cdcacm.h" // USB CDC ACM header and definitions
|
||||
|
||||
/** maximum packet size for USB data transfer */
|
||||
#define USB_DATA_TRANSFER_SIZE 64
|
||||
|
||||
static uint8_t usbd_control_buffer[128] = {0}; /**< buffer to be used for control requests */
|
||||
static usbd_device *usb_device = NULL; /**< structure holding all the info related to the USB device */
|
||||
|
||||
/* output ring buffer, index, and available memory */
|
||||
static uint8_t tx_buffer[512] = {0}; /**< ring buffer for data to transmit */
|
||||
static volatile uint16_t tx_i = 0; /**< current position if transmitted data */
|
||||
static volatile uint16_t tx_used = 0; /**< how much data needs to be transmitted */
|
||||
static volatile bool tx_lock = false; /**< if the transmit buffer is currently being written */
|
||||
static bool connected = false; /**< is the USB device is connected to a host */
|
||||
|
||||
/** USB CDC ACM device descriptor
|
||||
* @note as defined in USB CDC specification section 5
|
||||
*/
|
||||
|
@ -68,19 +77,19 @@ static const struct usb_endpoint_descriptor usb_cdcacm_data_endpoints[] = {{
|
|||
.bDescriptorType = USB_DT_ENDPOINT, /**< a value of 5 indicates that this describes an endpoint */
|
||||
.bEndpointAddress = 0x02, /**< OUT (from host) direction (0<<7), endpoint 2 */
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK, /**< bulk mode */
|
||||
.wMaxPacketSize = 64, /**< maximum packet size */
|
||||
.wMaxPacketSize = USB_DATA_TRANSFER_SIZE, /**< maximum packet size */
|
||||
.bInterval = 1, /**< the frequency, in number of frames, that we're going to be sending data */
|
||||
},{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE, /**< the size of the endpoint descriptor in bytes */
|
||||
.bDescriptorType = USB_DT_ENDPOINT, /**< a value of 5 indicates that this describes an endpoint */
|
||||
.bEndpointAddress = 0x82, /**< IN (to host) direction (1<<7), endpoint 2 */
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK, /**< bulk mode */
|
||||
.wMaxPacketSize = 64, /**< maximum packet size */
|
||||
.wMaxPacketSize = USB_DATA_TRANSFER_SIZE, /**< maximum packet size */
|
||||
.bInterval = 1, /**< the frequency, in number of frames, that we're going to be sending data */
|
||||
}};
|
||||
|
||||
/** USB CDC ACM communication endpoints
|
||||
* @note This notification endpoint isn't implemented. According to CDC spec its optional, but its absence causes a NULL pointer dereference in Linux cdc_acm driver
|
||||
* @note This notification endpoint isn't implemented. According to CDC spec its optional, but its absence causes a NULL pointer dereference in Linux cdc_acm driver
|
||||
*/
|
||||
static const struct usb_endpoint_descriptor usb_cdcacm_communication_endpoints[] = {{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE, /**< the size of the endpoint descriptor in bytes */
|
||||
|
@ -162,6 +171,7 @@ static const struct usb_interface_descriptor usb_cdcacm_data_interface = {
|
|||
.bInterfaceSubClass = 0, /**< USB CDC ACM interface subclass */
|
||||
.bInterfaceProtocol = 0, /**< USB CDC ACM none protocol */
|
||||
.iInterface = 0, /**< the index of the string in the string table that represents interface description */
|
||||
|
||||
.endpoint = usb_cdcacm_data_endpoints, /**< point to endpoint descriptor */
|
||||
};
|
||||
|
||||
|
@ -229,13 +239,6 @@ static const char *usb_strings[] = {
|
|||
"DFU bootloader (runtime mode)", /**< DFU interface string */
|
||||
};
|
||||
|
||||
/* output ring buffer, index, and available memory */
|
||||
static uint8_t tx_buffer[64] = {0}; /**< ring buffer for data to transmit */
|
||||
static volatile uint8_t tx_i = 0; /**< current position if transmitted data */
|
||||
static volatile uint8_t tx_used = 0; /**< how much data needs to be transmitted */
|
||||
mutex_t tx_lock = MUTEX_UNLOCKED; /**< lock to update tx_i or tx_used */
|
||||
static bool connected = false; /**< is the USB device is connected to a host */
|
||||
|
||||
/** disconnect USB by pulling down D+ to for re-enumerate */
|
||||
static void usb_disconnect(void)
|
||||
{
|
||||
|
@ -369,7 +372,7 @@ static void usb_cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
|
|||
{
|
||||
(void)ep;
|
||||
|
||||
char usb_data[64] = {0}; // buffer to read data
|
||||
char usb_data[USB_DATA_TRANSFER_SIZE] = {0}; // buffer to read data
|
||||
uint16_t usb_length = 0; // length of incoming data
|
||||
|
||||
/* receive data */
|
||||
|
@ -393,13 +396,12 @@ static void usb_cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
|
|||
if (!usbd_dev || !connected || !tx_used) { // verify if we can send and there is something to send
|
||||
return;
|
||||
}
|
||||
if (mutex_trylock(&tx_lock)) { // try to get lock
|
||||
uint8_t usb_length = (tx_used > 64 ? 64 : tx_used); // length of data to be transmitted (respect max packet size)
|
||||
if (!tx_lock) {
|
||||
uint8_t usb_length = (tx_used > USB_DATA_TRANSFER_SIZE ? USB_DATA_TRANSFER_SIZE : tx_used); // length of data to be transmitted (respect max packet size)
|
||||
usb_length = (usb_length > (LENGTH(tx_buffer)-tx_i) ? LENGTH(tx_buffer)-tx_i : usb_length); // since here we use the source array not as ring buffer, only go up to the end
|
||||
while (usb_length != usbd_ep_write_packet(usb_device, 0x82, (void*)(&tx_buffer[tx_i]), usb_length)); // ensure data is written into transmit buffer
|
||||
tx_i = (tx_i+usb_length)%LENGTH(tx_buffer); // update location on buffer
|
||||
tx_used -= usb_length; // update used size
|
||||
mutex_unlock(&tx_lock); // release lock
|
||||
} else {
|
||||
usbd_ep_write_packet(usb_device, 0x82, NULL, 0); // trigger empty tx for a later callback
|
||||
}
|
||||
|
@ -415,12 +417,12 @@ static void usb_cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
|||
(void)wValue;
|
||||
|
||||
usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
||||
usbd_ep_setup(usbd_dev, 0x02, USB_ENDPOINT_ATTR_BULK, 64, usb_cdcacm_data_rx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, usb_cdcacm_data_tx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x02, USB_ENDPOINT_ATTR_BULK, USB_DATA_TRANSFER_SIZE, usb_cdcacm_data_rx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, USB_DATA_TRANSFER_SIZE, usb_cdcacm_data_tx_cb);
|
||||
|
||||
usbd_register_control_callback( usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, usb_cdcacm_control_request);
|
||||
}
|
||||
|
||||
|
||||
void usb_cdcacm_setup(void)
|
||||
{
|
||||
connected = false; // start with USB not connected
|
||||
|
@ -437,7 +439,7 @@ void usb_cdcacm_setup(void)
|
|||
// reset buffer states
|
||||
tx_i = 0;
|
||||
tx_used = 0;
|
||||
mutex_unlock(&tx_lock);
|
||||
tx_lock = false; // release lock
|
||||
}
|
||||
|
||||
void usb_cdcacm_putchar(char c)
|
||||
|
@ -445,7 +447,7 @@ void usb_cdcacm_putchar(char c)
|
|||
if (!usb_device || !connected) {
|
||||
return;
|
||||
}
|
||||
mutex_lock(&tx_lock); // get lock to prevent race condition
|
||||
tx_lock = true; // put lock on transmit buffer
|
||||
if (tx_used<LENGTH(tx_buffer)) { // buffer not full
|
||||
tx_buffer[(tx_i+tx_used)%LENGTH(tx_buffer)] = c; // put character in buffer
|
||||
tx_used++; // update used buffer
|
||||
|
@ -453,8 +455,8 @@ void usb_cdcacm_putchar(char c)
|
|||
tx_i = (tx_i+1)%LENGTH(tx_buffer); // shift start
|
||||
tx_buffer[(tx_i+tx_used)%LENGTH(tx_buffer)] = c; // overwrite old data
|
||||
}
|
||||
mutex_unlock(&tx_lock); // release lock
|
||||
if (tx_used==1) { // to buffer is not empty anymore
|
||||
tx_lock = false; // release lock on transmit buffer
|
||||
if (tx_used>0) { // to buffer is not empty anymore
|
||||
usbd_ep_write_packet(usb_device, 0x82, NULL, 0); // trigger tx callback
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue