28 #include <libopencm3/stm32/rcc.h>
29 #include <libopencm3/stm32/gpio.h>
30 #include <libopencm3/cm3/nvic.h>
31 #include <libopencm3/cm3/scb.h>
32 #include <libopencmsis/core_cm3.h>
33 #include <libopencm3/usb/usbd.h>
34 #include <libopencm3/usb/cdc.h>
35 #include <libopencm3/cm3/sync.h>
44 .bLength = USB_DT_DEVICE_SIZE,
45 .bDescriptorType = USB_DT_DEVICE,
47 .bDeviceClass = USB_CLASS_CDC,
50 .bMaxPacketSize0 = 64,
57 .bNumConfigurations = 1,
64 .bLength = USB_DT_ENDPOINT_SIZE,
65 .bDescriptorType = USB_DT_ENDPOINT,
66 .bEndpointAddress = 0x01,
67 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
71 .bLength = USB_DT_ENDPOINT_SIZE,
72 .bDescriptorType = USB_DT_ENDPOINT,
73 .bEndpointAddress = 0x82,
74 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
83 .bLength = USB_DT_ENDPOINT_SIZE,
84 .bDescriptorType = USB_DT_ENDPOINT,
85 .bEndpointAddress = 0x83,
86 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
96 struct usb_cdc_header_descriptor header;
97 struct usb_cdc_call_management_descriptor call_mgmt;
98 struct usb_cdc_acm_descriptor acm;
99 struct usb_cdc_union_descriptor cdc_union;
102 .bFunctionLength =
sizeof(
struct usb_cdc_header_descriptor),
103 .bDescriptorType = CS_INTERFACE,
104 .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
108 .bFunctionLength =
sizeof(
struct usb_cdc_call_management_descriptor),
109 .bDescriptorType = CS_INTERFACE,
110 .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
115 .bFunctionLength =
sizeof(
struct usb_cdc_acm_descriptor),
116 .bDescriptorType = CS_INTERFACE,
117 .bDescriptorSubtype = USB_CDC_TYPE_ACM,
121 .bFunctionLength =
sizeof(
struct usb_cdc_union_descriptor),
122 .bDescriptorType = CS_INTERFACE,
123 .bDescriptorSubtype = USB_CDC_TYPE_UNION,
124 .bControlInterface = 0,
125 .bSubordinateInterface0 = 1,
133 .bLength = USB_DT_INTERFACE_SIZE,
134 .bDescriptorType = USB_DT_INTERFACE,
135 .bInterfaceNumber = 0,
136 .bAlternateSetting = 0,
138 .bInterfaceClass = USB_CLASS_CDC,
139 .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
140 .bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
145 .extra = &cdcacm_functional_descriptors,
146 .extralen =
sizeof(cdcacm_functional_descriptors),
153 .bLength = USB_DT_INTERFACE_SIZE,
154 .bDescriptorType = USB_DT_INTERFACE,
155 .bInterfaceNumber = 1,
156 .bAlternateSetting = 0,
158 .bInterfaceClass = USB_CLASS_DATA,
159 .bInterfaceSubClass = 0,
160 .bInterfaceProtocol = 0,
176 static const struct usb_config_descriptor
config = {
177 .bLength = USB_DT_CONFIGURATION_SIZE,
178 .bDescriptorType = USB_DT_CONFIGURATION,
181 .bConfigurationValue = 1,
183 .bmAttributes = 0x80,
204 static volatile uint8_t
rx_i = 0;
208 static volatile uint8_t
tx_i = 0;
217 #if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
219 rcc_periph_clock_enable(RCC_GPIOA);
220 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
221 gpio_clear(GPIOA, GPIO12);
222 for (uint32_t i = 0; i < 0x2000; i++) {
225 #elif defined(MAPLE_MINI)
227 rcc_periph_clock_enable(RCC_GPIOB);
228 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO9);
229 gpio_set(GPIOB, GPIO9);
230 for (uint32_t i = 0; i < 0x2000; i++) {
233 gpio_clear(GPIOB, GPIO9);
246 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))
252 switch (req->bRequest) {
253 case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
254 connected = req->wValue ?
true :
false;
261 uint8_t reply[10] = {0};
262 struct usb_cdc_notification *notif = (
void *)reply;
264 notif->bmRequestType = 0xA1;
265 notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
269 reply[8] = req->wValue & 3;
271 usbd_ep_write_packet(usbd_dev, 0x83, reply,
LENGTH(reply));
273 case USB_CDC_REQ_SET_LINE_CODING:
275 if (*len <
sizeof(
struct usb_cdc_line_coding)) {
279 struct usb_cdc_line_coding *coding = (
struct usb_cdc_line_coding *)*buf;
284 if (coding->bDataBits==5) {
304 char usb_data[64] = {0};
305 uint16_t usb_length = 0;
308 usb_length = usbd_ep_read_packet(usbd_dev, 0x01, usb_data,
sizeof(usb_data));
310 for (uint16_t i=0; i<usb_length && rx_used<
LENGTH(rx_buffer); i++) {
327 if (!usbd_dev || !connected || !tx_used) {
330 if (mutex_trylock(&tx_lock)) {
331 uint8_t usb_length = (tx_used > 64 ? 64 :
tx_used);
332 usb_length = (usb_length > (
LENGTH(tx_buffer)-
tx_i) ?
LENGTH(tx_buffer)-tx_i : usb_length);
333 while (usb_length != usbd_ep_write_packet(usb_device, 0x82, (
void*)(&tx_buffer[
tx_i]), usb_length));
334 tx_i = (tx_i+usb_length)%
LENGTH(tx_buffer);
335 tx_used -= usb_length;
336 mutex_unlock(&tx_lock);
338 usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
340 usbd_poll(usb_device);
353 usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
355 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);
364 usb_device = usbd_init(&st_usbfs_v1_usb_driver, &
device_descriptor, &config, usb_strings, 3, usbd_control_buffer,
sizeof(usbd_control_buffer));
368 nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
373 mutex_unlock(&rx_lock);
377 mutex_unlock(&tx_lock);
385 char to_return = rx_buffer[
rx_i];
386 rx_i = (rx_i+1)%
LENGTH(rx_buffer);
394 if (!usb_device || !connected) {
397 mutex_lock(&tx_lock);
398 if (tx_used<
LENGTH(tx_buffer)) {
402 tx_i = (tx_i+1)%
LENGTH(tx_buffer);
405 mutex_unlock(&tx_lock);
406 usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
411 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
void cdcacm_putchar(char c)
send character over USB (non-blocking)
static uint8_t rx_buffer[CDCACM_BUFFER]
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]
static volatile uint8_t rx_used
static const struct usb_interface_descriptor communication_interface[]
USB CDC interface descriptor.
volatile uint8_t cdcacm_received
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
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]
library for USB CDC ACM communication (API)
static const struct usb_device_descriptor device_descriptor
USB CDC ACM device descriptor.
static volatile uint8_t rx_i
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
static usbd_device * usb_device
char cdcacm_getchar(void)
get character received over USB (blocking)