From 47ecbbbecbad117820e1c37282e7e61528e5d969 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 May 2018 23:44:45 +1000 Subject: [PATCH] stm32/usb: Add ability to have 2x VCP interfaces on the one USB device. This patch adds the configuration MICROPY_HW_USB_ENABLE_CDC2 which enables a new USB device configuration at runtime: VCP+VCP+MSC. It will give two independent VCP interfaces available via pyb.USB_VCP(0) and pyb.USB_VCP(1). The first one is the usual one and has the REPL on it. The second one is available for general use. This configuration is disabled by default because if the mode is not used then it takes up about 2200 bytes of RAM. Also, F4 MCUs can't support this mode on their USB FS peripheral (eg PYBv1.x) because they don't have enough endpoints. The USB HS peripheral of an F4 supports it, as well as both the USB FS and USB HS peripherals of F7 MCUs. --- ports/stm32/usb.c | 42 +++- ports/stm32/usb.h | 1 + ports/stm32/usbd_cdc_interface.c | 22 +- ports/stm32/usbd_cdc_interface.h | 4 + ports/stm32/usbd_conf.c | 42 +++- ports/stm32/usbd_conf.h | 2 +- .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h | 8 + .../usbdev/class/inc/usbd_cdc_msc_hid0.h | 8 +- .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 203 +++++++++++++----- 9 files changed, 257 insertions(+), 75 deletions(-) diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 7e30805cce..23c490d375 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -63,6 +63,9 @@ typedef struct _usb_device_t { USBD_HandleTypeDef hUSBDDevice; usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state; usbd_cdc_itf_t usbd_cdc_itf; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_itf_t usbd_cdc2_itf; + #endif usbd_hid_itf_t usbd_hid_itf; } usb_device_t; @@ -127,6 +130,9 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H usbd->pClass = &USBD_CDC_MSC_HID; usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; + #endif usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; @@ -178,6 +184,15 @@ void usb_vcp_send_strn(const char *str, int len) { } } +usbd_cdc_itf_t *usb_vcp_get(int idx) { + #if MICROPY_HW_USB_ENABLE_CDC2 + if (idx == 1) { + return &usb_device.usbd_cdc2_itf; + } + #endif + return &usb_device.usbd_cdc_itf; +} + /******************************************************************************/ // MicroPython bindings for USB @@ -285,6 +300,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2_MSC; + } + mode = USBD_MODE_CDC2_MSC; + #endif } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC_HID; @@ -358,21 +380,33 @@ typedef struct _pyb_usb_vcp_obj_t { } pyb_usb_vcp_obj_t; STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; +#if MICROPY_HW_USB_ENABLE_CDC2 +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf}; +#endif STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_print_str(print, "USB_VCP()"); + int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf; + mp_printf(print, "USB_VCP(%u)", id); } /// \classmethod \constructor() /// Create a new USB_VCP object. STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 0, 1, false); // TODO raise exception if USB is not configured for VCP - // return the USB VCP object - return (mp_obj_t)&pyb_usb_vcp_obj; + int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]); + if (id == 0) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (id == 1) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj); + #endif + } else { + mp_raise_ValueError(NULL); + } } STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 6b43af00fa..1de9e5d0e5 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -36,6 +36,7 @@ #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) #define USBD_PID_MSC (0x9803) +#define USBD_PID_CDC2_MSC (0x9804) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 3ab6157c46..4c464dbf33 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -69,6 +69,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { cdc->tx_buf_ptr_wait_count = 0; cdc->tx_need_empty_packet = 0; cdc->dev_is_connected = 0; + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc; + #else + cdc->attached_to_repl = 1; + #endif // Return the buffer to place the first USB OUT packet return cdc->rx_packet_buf; @@ -143,10 +148,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui // This function is called to process outgoing data. We hook directly into the // SOF (start of frame) callback so that it is called exactly at the time it is // needed (reducing latency), and often enough (increasing bandwidth). -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { - usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; - +static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) { if (cdc == NULL || !cdc->dev_is_connected) { // CDC device is not connected to a host, so we are unable to send any data return; @@ -199,11 +201,19 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc); + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2); + #endif +} + // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL @@ -212,7 +222,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { // copy the incoming data into the circular buffer for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { - if (mp_interrupt_char != -1 && *src == mp_interrupt_char) { + if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) { pendsv_kbd_intr(); } else { uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1); diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index bfcdfaf333..cdf556d4ec 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t { 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 dev_is_connected; // indicates if we are connected + uint8_t attached_to_repl; // indicates if interface is connected to REPL } 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->dev_is_connected; } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d4a09459b8..7829dcce68 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -368,7 +368,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { if (pdev->id == USB_PHY_FS_ID) { // Set LL Driver parameters pcd_fs_handle.Instance = USB_OTG_FS; + #if MICROPY_HW_USB_ENABLE_CDC2 + pcd_fs_handle.Init.dev_endpoints = 6; + #else pcd_fs_handle.Init.dev_endpoints = 4; + #endif pcd_fs_handle.Init.use_dedicated_ep1 = 0; pcd_fs_handle.Init.ep0_mps = 0x40; pcd_fs_handle.Init.dma_enable = 0; @@ -393,11 +397,22 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); - HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); + // We have 320 32-bit words in total to use here + #if MICROPY_HW_USB_ENABLE_CDC2 + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA + #else + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA + #endif } #endif #if MICROPY_HW_USB_HS @@ -406,11 +421,13 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Set LL Driver parameters pcd_hs_handle.Instance = USB_OTG_HS; - pcd_hs_handle.Init.dev_endpoints = 4; + pcd_hs_handle.Init.dev_endpoints = 6; pcd_hs_handle.Init.use_dedicated_ep1 = 0; pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.lpm_enable = DISABLE; + pcd_hs_handle.Init.battery_charging_enable = DISABLE; #if defined(STM32F723xx) || defined(STM32F733xx) pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; #else @@ -436,11 +453,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_hs_handle); - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); + // We have 1024 32-bit words in total to use here + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 512); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 64); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 32); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 64); // CDC2 DATA #else // !MICROPY_HW_USB_HS_IN_FS diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index e68cbd9a4b..1f8e754a2b 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -37,7 +37,7 @@ #include #include -#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_INTERFACES 4 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #define USBD_SELF_POWERED 0 diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 8bf454558a..a4f81f10d9 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -20,7 +20,11 @@ // Needed for the CDC+MSC+HID state and should be maximum of all template // config descriptors defined in usbd_cdc_msc_hid.c +#if MICROPY_HW_USB_ENABLE_CDC2 +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#else #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +#endif // CDC, MSC and HID packet sizes #define MSC_FS_MAX_PACKET (64) @@ -46,6 +50,7 @@ typedef struct { uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment uint8_t iface_num; uint8_t in_ep; + uint8_t out_ep; uint8_t cur_request; uint8_t cur_length; volatile uint8_t tx_in_progress; @@ -120,6 +125,9 @@ typedef struct _usbd_cdc_msc_hid_state_t { __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; usbd_cdc_state_t *cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_state_t *cdc2; + #endif usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 95fc693a00..c876dcf298 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -34,9 +34,11 @@ typedef enum { USBD_MODE_CDC = 0x01, USBD_MODE_MSC = 0x02, USBD_MODE_HID = 0x04, - USBD_MODE_CDC_MSC = 0x03, - USBD_MODE_CDC_HID = 0x05, - USBD_MODE_MSC_HID = 0x06, + USBD_MODE_CDC2 = 0x08, + USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC, + USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID, + USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID, + USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2, USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 6def258c60..d0b922d761 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -34,6 +34,10 @@ #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) #define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) #define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) @@ -57,6 +61,7 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_MSC (3) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) @@ -66,6 +71,10 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) +#define CDC2_IN_EP (0x85) +#define CDC2_OUT_EP (0x05) +#define CDC2_CMD_EP (0x84) + #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) @@ -625,6 +634,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: { + usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength + d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); + d[4] = 5; // bNumInterfaces + memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58); + d += 9 + 23 + (8 + 58); + d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface + d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber + d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface + d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface + d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface + d[38] = CDC2_CMD_EP; // bEndpointAddress + d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber + d[54] = CDC2_OUT_EP; // bEndpointAddress + d[61] = CDC2_IN_EP; // bEndpointAddress + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + break; + } + #endif + case USBD_MODE_CDC_HID: usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); @@ -657,8 +691,16 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode if (usbd->usbd_mode & USBD_MODE_CDC) { usbd->cdc->in_ep = CDC_IN_EP; + usbd->cdc->out_ep = CDC_OUT_EP; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + usbd->cdc2->in_ep = CDC2_IN_EP; + usbd->cdc2->out_ep = CDC2_OUT_EP; + } + #endif + // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { uint8_t *hid_desc = usbd->hid->desc; @@ -677,6 +719,26 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return 0; } +static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) { + int mp = usbd_cdc_max_packet(pdev); + + // Open endpoints + USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); + + // Init state + cdc->usbd = usbd; + cdc->cur_request = 0xff; + cdc->tx_in_progress = 0; + + // Init interface + uint8_t *buf = usbd_cdc_init(cdc); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp); +} + static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { @@ -689,39 +751,16 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component - - int mp = usbd_cdc_max_packet(pdev); - - // Open EP IN - USBD_LL_OpenEP(pdev, - CDC_IN_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open EP OUT - USBD_LL_OpenEP(pdev, - CDC_OUT_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open Command IN EP - USBD_LL_OpenEP(pdev, - CDC_CMD_EP, - USBD_EP_TYPE_INTR, - CDC_CMD_PACKET_SIZE); - - // Init Xfer states - usbd->cdc->usbd = usbd; - usbd->cdc->cur_request = 0xff; - usbd->cdc->tx_in_progress = 0; - - // Init physical Interface components - uint8_t *buf = usbd_cdc_init(usbd->cdc); - - // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); + usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + // CDC VCP #2 component + usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -785,6 +824,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) USBD_LL_CloseEP(pdev, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { + // CDC VCP #2 component + + // close endpoints + USBD_LL_CloseEP(pdev, CDC2_IN_EP); + USBD_LL_CloseEP(pdev, CDC2_OUT_EP); + USBD_LL_CloseEP(pdev, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -830,11 +880,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Work out the recipient of the setup request uint8_t mode = usbd->usbd_mode; uint8_t recipient = 0; + usbd_cdc_state_t *cdc; switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { case USB_REQ_RECIPIENT_INTERFACE: { uint16_t iface = req->wIndex; if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { @@ -846,6 +903,12 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp uint8_t ep = req->wIndex & 0x7f; if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { @@ -869,18 +932,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request - usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); - USBD_CtlSendData(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } else { // host-to-device request - usbd->cdc->cur_request = req->bRequest; - usbd->cdc->cur_length = req->wLength; - USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + cdc->cur_request = req->bRequest; + cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } } else { // Not a Data request // Transfer the command to the interface layer - return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); + return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); } } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { @@ -1002,6 +1065,12 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); usbd->cdc->cur_request = 0xff; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length); + usbd->cdc2->cur_request = 0xff; + } + #endif return USBD_OK; } @@ -1011,6 +1080,11 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { usbd->cdc->tx_in_progress = 0; return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) { + usbd->cdc2->tx_in_progress = 0; + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; @@ -1035,6 +1109,12 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) usbd_cdc_receive(usbd->cdc, len); return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_cdc_receive(usbd->cdc2, len); + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; @@ -1046,11 +1126,31 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) return USBD_OK; } +#if USBD_SUPPORT_HS_MODE +static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; +} +#endif + static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; #if USBD_SUPPORT_HS_MODE uint8_t *cdc_desc = NULL; + #if MICROPY_HW_USB_ENABLE_CDC2 + uint8_t *cdc2_desc = NULL; + #endif uint8_t *msc_desc = NULL; switch (usbd->usbd_mode) { case USBD_MODE_MSC: @@ -1062,6 +1162,14 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: + cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + case USBD_MODE_CDC_HID: cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; break; @@ -1073,20 +1181,15 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * // configure CDC descriptors, if needed if (cdc_desc != NULL) { - uint32_t mp = usbd_cdc_max_packet(pdev); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); - uint8_t interval; // polling interval in frames of 1ms - if (pdev->dev_speed == USBD_SPEED_HIGH) { - interval = 0x09; - } else { - interval = 0x20; - } - cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; + usbd_cdc_desc_config_max_packet(pdev, cdc_desc); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (cdc2_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc2_desc); + } + #endif + if (msc_desc != NULL) { uint32_t mp = usbd_msc_max_packet(pdev); msc_desc[13] = LOBYTE(mp); @@ -1135,7 +1238,7 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(cdc->usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); + USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); return USBD_OK; }