27 #include <libopencm3/stm32/rcc.h>
28 #include <libopencm3/stm32/gpio.h>
29 #include <libopencm3/cm3/nvic.h>
30 #include <libopencm3/cm3/scb.h>
31 #include <libopencmsis/core_cm3.h>
32 #include <libopencm3/usb/usbd.h>
33 #include <libopencm3/usb/cdc.h>
34 #include <libopencm3/cm3/sync.h>
43 .bLength = USB_DT_DEVICE_SIZE,
44 .bDescriptorType = USB_DT_DEVICE,
46 .bDeviceClass = USB_CLASS_CDC,
49 .bMaxPacketSize0 = 64,
56 .bNumConfigurations = 1,
63 .bLength = USB_DT_ENDPOINT_SIZE,
64 .bDescriptorType = USB_DT_ENDPOINT,
65 .bEndpointAddress = 0x01,
66 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
70 .bLength = USB_DT_ENDPOINT_SIZE,
71 .bDescriptorType = USB_DT_ENDPOINT,
72 .bEndpointAddress = 0x82,
73 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
82 .bLength = USB_DT_ENDPOINT_SIZE,
83 .bDescriptorType = USB_DT_ENDPOINT,
84 .bEndpointAddress = 0x83,
85 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
95 struct usb_cdc_header_descriptor header;
96 struct usb_cdc_call_management_descriptor call_mgmt;
97 struct usb_cdc_acm_descriptor acm;
98 struct usb_cdc_union_descriptor cdc_union;
101 .bFunctionLength =
sizeof(
struct usb_cdc_header_descriptor),
102 .bDescriptorType = CS_INTERFACE,
103 .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
107 .bFunctionLength =
sizeof(
struct usb_cdc_call_management_descriptor),
108 .bDescriptorType = CS_INTERFACE,
109 .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
114 .bFunctionLength =
sizeof(
struct usb_cdc_acm_descriptor),
115 .bDescriptorType = CS_INTERFACE,
116 .bDescriptorSubtype = USB_CDC_TYPE_ACM,
120 .bFunctionLength =
sizeof(
struct usb_cdc_union_descriptor),
121 .bDescriptorType = CS_INTERFACE,
122 .bDescriptorSubtype = USB_CDC_TYPE_UNION,
123 .bControlInterface = 0,
124 .bSubordinateInterface0 = 1,
132 .bLength = USB_DT_INTERFACE_SIZE,
133 .bDescriptorType = USB_DT_INTERFACE,
134 .bInterfaceNumber = 0,
135 .bAlternateSetting = 0,
137 .bInterfaceClass = USB_CLASS_CDC,
138 .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
139 .bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
144 .extra = &cdcacm_functional_descriptors,
145 .extralen =
sizeof(cdcacm_functional_descriptors),
152 .bLength = USB_DT_INTERFACE_SIZE,
153 .bDescriptorType = USB_DT_INTERFACE,
154 .bInterfaceNumber = 1,
155 .bAlternateSetting = 0,
157 .bInterfaceClass = USB_CLASS_DATA,
158 .bInterfaceSubClass = 0,
159 .bInterfaceProtocol = 0,
175 static const struct usb_config_descriptor
config = {
176 .bLength = USB_DT_CONFIGURATION_SIZE,
177 .bDescriptorType = USB_DT_CONFIGURATION,
180 .bConfigurationValue = 1,
182 .bmAttributes = 0x80,
203 static volatile uint8_t
rx_i = 0;
207 static volatile uint8_t
tx_i = 0;
216 #if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
218 rcc_periph_clock_enable(RCC_GPIOA);
219 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
220 gpio_clear(GPIOA, GPIO12);
221 for (uint32_t i = 0; i < 0x2000; i++) {
224 #elif defined(MAPLE_MINI)
226 rcc_periph_clock_enable(RCC_GPIOB);
227 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO9);
228 gpio_set(GPIOB, GPIO9);
229 for (uint32_t i = 0; i < 0x2000; i++) {
232 gpio_clear(GPIOB, GPIO9);
245 static int cdcacm_control_request(usbd_device *usbd_dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *usbd_dev,
struct usb_setup_data *req))
251 switch (req->bRequest) {
252 case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
253 connected = req->wValue ?
true :
false;
260 uint8_t reply[10] = {0};
261 struct usb_cdc_notification *notif = (
void *)reply;
263 notif->bmRequestType = 0xA1;
264 notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
268 reply[8] = req->wValue & 3;
270 usbd_ep_write_packet(usbd_dev, 0x83, reply,
LENGTH(reply));
272 case USB_CDC_REQ_SET_LINE_CODING:
274 if (*len <
sizeof(
struct usb_cdc_line_coding)) {
278 struct usb_cdc_line_coding *coding = (
struct usb_cdc_line_coding *)*buf;
283 if (coding->bDataBits==5) {
303 char usb_data[64] = {0};
304 uint16_t usb_length = 0;
307 usb_length = usbd_ep_read_packet(usbd_dev, 0x01, usb_data,
sizeof(usb_data));
309 for (uint16_t i=0; i<usb_length && rx_used<
LENGTH(rx_buffer); i++) {
326 if (!usbd_dev || !connected || !tx_used) {
329 if (mutex_trylock(&tx_lock)) {
330 uint8_t usb_length = (tx_used > 64 ? 64 :
tx_used);
331 usb_length = (usb_length > (
LENGTH(tx_buffer)-
tx_i) ?
LENGTH(tx_buffer)-tx_i : usb_length);
332 while (usb_length != usbd_ep_write_packet(usb_device, 0x82, (
void*)(&tx_buffer[
tx_i]), usb_length));
333 tx_i = (tx_i+usb_length)%
LENGTH(tx_buffer);
334 tx_used -= usb_length;
335 mutex_unlock(&tx_lock);
337 usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
339 usbd_poll(usb_device);
352 usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
354 usbd_register_control_callback( usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
cdcacm_control_request);
363 usb_device = usbd_init(&st_usbfs_v1_usb_driver, &
device_descriptor, &config, usb_strings, 3, usbd_control_buffer,
sizeof(usbd_control_buffer));
367 nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
372 mutex_unlock(&rx_lock);
376 mutex_unlock(&tx_lock);
384 char to_return = rx_buffer[
rx_i];
385 rx_i = (rx_i+1)%
LENGTH(rx_buffer);
393 if (!usb_device || !connected) {
396 mutex_lock(&tx_lock);
397 if (tx_used<
LENGTH(tx_buffer)) {
401 tx_i = (tx_i+1)%
LENGTH(tx_buffer);
404 mutex_unlock(&tx_lock);
406 usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
412 usbd_poll(usb_device);
static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void(**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
incoming USB CDC ACM control request
static const struct usb_interface interfaces[]
USB CDC ACM interface descriptor.
static volatile uint8_t tx_i
current position if transmitted data
void cdcacm_putchar(char c)
send character over USB (non-blocking)
static uint8_t rx_buffer[CDCACM_BUFFER]
ring buffer for received data
static const struct @0 __attribute__((packed))
USB CDC ACM functional descriptor.
global definitions and methods
static void cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
USB CDC ACM data transmitted callback.
static const struct usb_config_descriptor config
USB CDC ACM configuration descriptor.
static const struct usb_endpoint_descriptor data_endpoints[]
USB CDC ACM data endpoints.
void cdcacm_setup(void)
setup USB CDC ACM peripheral
static uint8_t usbd_control_buffer[128]
buffer to be used for control requests
static volatile uint8_t rx_used
how much data has been received and not red
mutex_t rx_lock
lock to update rx_i or rx_used
static const struct usb_interface_descriptor communication_interface[]
USB CDC interface descriptor.
volatile uint8_t cdcacm_received
how many bytes available in the received buffer since last read
static const char * usb_strings[]
USB string table.
static void usb_disconnect(void)
disconnect USB by pulling down D+ to for re-enumerate
static const struct usb_interface_descriptor data_interface[]
USB CDC ACM data class interface descriptor.
static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
set USB CDC ACM configuration
static bool connected
is the USB device is connected to a host
void usb_lp_can_rx0_isr(void)
USB interrupt service routine called when data is received.
static const struct usb_endpoint_descriptor communication_endpoints[]
USB CDC ACM communication endpoints.
static uint8_t tx_buffer[CDCACM_BUFFER]
ring buffer for data to transmit
library for USB CDC ACM communication (API)
#define LENGTH(x)
get the length of an array
static const struct usb_device_descriptor device_descriptor
USB CDC ACM device descriptor.
static volatile uint8_t rx_i
current position of read received data
#define CDCACM_BUFFER
transmit and receive buffer sizes
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
USB CDC ACM data received callback.
static volatile uint8_t tx_used
how much data needs to be transmitted
static usbd_device * usb_device
structure holding all the info related to the USB device
mutex_t tx_lock
lock to update tx_i or tx_used
char cdcacm_getchar(void)
get character received over USB (blocking)