From 64b8097f342ea36f24efe7d9f0008742ca1ab65b Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 2 May 2023 17:19:56 +0200 Subject: [PATCH] USB CDC works --- .gitmodules | 3 + Makefile | 6 +- src/main.c | 273 ++++++++++++++++++++++++++++++++++++++++-- upstream/libusb_stm32 | 1 + 4 files changed, 274 insertions(+), 9 deletions(-) create mode 100644 .gitmodules create mode 160000 upstream/libusb_stm32 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a3dadfe --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "upstream/libusb_stm32"] + path = upstream/libusb_stm32 + url = https://github.com/dmitrystu/libusb_stm32 diff --git a/Makefile b/Makefile index 0d33f0f..2412a52 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,9 @@ DEVICE := STM32F072CB ASM_SOURCES := startup.s -C_SOURCES := src/main.c +C_SOURCES := src/main.c \ + upstream/libusb_stm32/src/usbd_stm32l052_devfs.c \ + upstream/libusb_stm32/src/usbd_core.c CPP_SOURCES := # - none - @@ -83,7 +85,7 @@ COMMON_CFLAGS += -I$(abspath include) COMMON_CFLAGS += -I$(BUILDDIR) CFLAGS += -I$(abspath tools/musl_include_shims) -CFLAGS += -I$(abspath $(TINYPRINTF_DIR)) +CFLAGS += -I$(abspath upstream/libusb_stm32/inc) CFLAGS += -I$(CMSIS_DEVICE_DIR_ABS)/Include CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS) diff --git a/src/main.c b/src/main.c index a21ef1d..24169db 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,9 @@ #include #include +#include +#include + struct adc_state { uint8_t txbuf[12]; uint8_t rxbuf[12]; @@ -544,6 +547,244 @@ void I2C1_IRQHandler() { } } + +#define USB_EP0_SIZE 8 +#define USB_CDC_RX_EP 0x01 +#define USB_CDC_TX_EP 0x81 +#define USB_CDC_DATA_SIZE 0x40 +#define USB_CDC_NTF_EP 0x82 +#define USB_CDC_NTF_SIZE 0x08 + +struct cdc_config { + struct usb_config_descriptor config; + struct usb_iad_descriptor comm_iad; + struct usb_interface_descriptor comm; + struct usb_cdc_header_desc cdc_hdr; + struct usb_cdc_call_mgmt_desc cdc_mgmt; + struct usb_cdc_acm_desc cdc_acm; + struct usb_cdc_union_desc cdc_union; + struct usb_endpoint_descriptor comm_ep; + struct usb_interface_descriptor data; + struct usb_endpoint_descriptor data_eprx; + struct usb_endpoint_descriptor data_eptx; +} __attribute__((packed)); + +static const struct usb_device_descriptor device_desc = { + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DTYPE_DEVICE, + .bcdUSB = VERSION_BCD(2,0,0), + .bDeviceClass = USB_CLASS_IAD, + .bDeviceSubClass = USB_SUBCLASS_IAD, + .bDeviceProtocol = USB_PROTO_IAD, + .bMaxPacketSize0 = USB_EP0_SIZE, + .idVendor = 0x0483, + .idProduct = 0x5740, + .bcdDevice = VERSION_BCD(1,0,0), + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = INTSERIALNO_DESCRIPTOR, + .bNumConfigurations = 1, +}; + +/* Device configuration descriptor */ +static const struct cdc_config config_desc = { + .config = { + .bLength = sizeof(struct usb_config_descriptor), + .bDescriptorType = USB_DTYPE_CONFIGURATION, + .wTotalLength = sizeof(struct cdc_config), + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = NO_DESCRIPTOR, + .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, + .bMaxPower = USB_CFG_POWER_MA(100), + }, + .comm_iad = { + .bLength = sizeof(struct usb_iad_descriptor), + .bDescriptorType = USB_DTYPE_INTERFASEASSOC, + .bFirstInterface = 0, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_CDC, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_PROTO_NONE, + .iFunction = NO_DESCRIPTOR, + }, + .comm = { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DTYPE_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_PROTO_NONE, + .iInterface = NO_DESCRIPTOR, + }, + .cdc_hdr = { + .bFunctionLength = sizeof(struct usb_cdc_header_desc), + .bDescriptorType = USB_DTYPE_CS_INTERFACE, + .bDescriptorSubType = USB_DTYPE_CDC_HEADER, + .bcdCDC = VERSION_BCD(1,1,0), + }, + .cdc_mgmt = { + .bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc), + .bDescriptorType = USB_DTYPE_CS_INTERFACE, + .bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + + }, + .cdc_acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_desc), + .bDescriptorType = USB_DTYPE_CS_INTERFACE, + .bDescriptorSubType = USB_DTYPE_CDC_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_desc), + .bDescriptorType = USB_DTYPE_CS_INTERFACE, + .bDescriptorSubType = USB_DTYPE_CDC_UNION, + .bMasterInterface0 = 0, + .bSlaveInterface0 = 1, + }, + .comm_ep = { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = USB_CDC_NTF_EP, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = USB_CDC_NTF_SIZE, + .bInterval = 0xFF, + }, + .data = { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DTYPE_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = USB_SUBCLASS_NONE, + .bInterfaceProtocol = USB_PROTO_NONE, + .iInterface = NO_DESCRIPTOR, + }, + .data_eprx = { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = USB_CDC_RX_EP, + .bmAttributes = USB_EPTYPE_BULK, + .wMaxPacketSize = USB_CDC_DATA_SIZE, + .bInterval = 0x01, + }, + .data_eptx = { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = USB_CDC_TX_EP, + .bmAttributes = USB_EPTYPE_BULK, + .wMaxPacketSize = USB_CDC_DATA_SIZE, + .bInterval = 0x01, + }, +}; + +static const struct usb_string_descriptor lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); +static const struct usb_string_descriptor manuf_desc_en = USB_STRING_DESC("TU Darmstadt, KOM / emergenCITY"); +static const struct usb_string_descriptor prod_desc_en = USB_STRING_DESC("IHSM rotor tester"); + +static struct usb_cdc_line_coding cdc_line = { + .dwDTERate = 115200, + .bCharFormat = USB_CDC_1_STOP_BITS, + .bParityType = USB_CDC_NO_PARITY, + .bDataBits = 8, +}; + +usbd_device usb_dev; +uint32_t usb_buf[0x20]; +uint8_t fifo[0x200]; +uint32_t fpos = 0; + +static usbd_respond usb_getdesc (usbd_ctlreq *req, void **address, uint16_t *length) { + const uint8_t dtype = req->wValue >> 8; + const uint8_t dnumber = req->wValue & 0xFF; + switch (dtype) { + case USB_DTYPE_DEVICE: *address = &device_desc; *length = device_desc.bLength; return usbd_ack; + case USB_DTYPE_CONFIGURATION: *address = &config_desc; *length = sizeof(config_desc); return usbd_ack; + case USB_DTYPE_STRING: break; + default: return usbd_fail; + } + + switch (dnumber) { + case 0: *address = &lang_desc; *length = lang_desc.bLength; return usbd_ack; + case 1: *address = &manuf_desc_en; *length = manuf_desc_en.bLength; return usbd_ack; + case 2: *address = &prod_desc_en; *length = prod_desc_en.bLength; return usbd_ack; + default: return usbd_fail; + } +} + + +static usbd_respond usb_control(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { + if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS) + && req->wIndex == 0 ) { + switch (req->bRequest) { + case USB_CDC_SET_CONTROL_LINE_STATE: + return usbd_ack; + case USB_CDC_SET_LINE_CODING: + memcpy(&cdc_line, req->data, sizeof(cdc_line)); + return usbd_ack; + case USB_CDC_GET_LINE_CODING: + dev->status.data_ptr = &cdc_line; + dev->status.data_count = sizeof(cdc_line); + return usbd_ack; + default: + return usbd_fail; + } + } + + return usbd_fail; +} + +static void usb_loopback(usbd_device *dev, uint8_t event, uint8_t ep) { + int _t; + if (fpos <= (sizeof(fifo) - USB_CDC_DATA_SIZE)) { + _t = usbd_ep_read(dev, USB_CDC_RX_EP, &fifo[fpos], USB_CDC_DATA_SIZE); + if (_t > 0) { + fpos += _t; + } + } + if (fpos > 0) { + _t = usbd_ep_write(dev, USB_CDC_TX_EP, &fifo[0], (fpos < USB_CDC_DATA_SIZE) ? fpos : USB_CDC_DATA_SIZE); + if (_t > 0) { + memmove(&fifo[0], &fifo[_t], fpos - _t); + fpos -= _t; + } + } +} + +static usbd_respond usb_setconf (usbd_device *dev, uint8_t cfg) { + switch (cfg) { + case 0: + /* deconfiguring device */ + usbd_ep_deconfig(dev, USB_CDC_NTF_EP); + usbd_ep_deconfig(dev, USB_CDC_TX_EP); + usbd_ep_deconfig(dev, USB_CDC_RX_EP); + usbd_reg_endpoint(dev, USB_CDC_RX_EP, 0); + usbd_reg_endpoint(dev, USB_CDC_TX_EP, 0); + return usbd_ack; + case 1: + /* configuring device */ + usbd_ep_config(dev, USB_CDC_RX_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, USB_CDC_DATA_SIZE); + usbd_ep_config(dev, USB_CDC_TX_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, USB_CDC_DATA_SIZE); + usbd_ep_config(dev, USB_CDC_NTF_EP, USB_EPTYPE_INTERRUPT, USB_CDC_NTF_SIZE); + usbd_reg_endpoint(dev, USB_CDC_RX_EP, usb_loopback); + usbd_reg_endpoint(dev, USB_CDC_TX_EP, usb_loopback); + usbd_ep_write(dev, USB_CDC_TX_EP, 0, 0); + return usbd_ack; + default: + return usbd_fail; + } +} + +void USB_IRQHandler() { + usbd_poll(&usb_dev); +} + + int main(void) { /* Enable HSE w/ 8 MHz crystal */ /* FIXME */ @@ -554,10 +795,10 @@ int main(void) { /* Configure PLL multiplier, clock dividers and MCO */ /* The ADS131M02 datasheet recommends an 8.192 MHz input clock for high-resolution mode. */ RCC->CFGR = (5<CR |= RCC_CR_PLLON; @@ -571,13 +812,19 @@ int main(void) { while (((RCC->CFGR & RCC_CFGR_SWS_Msk) >> RCC_CFGR_SWS_Pos) != 2) ; + /* Switch on HSI48 clock for USB */ + RCC->CR2 |= RCC_CR2_HSI48ON; + while (!(RCC->CR2 & RCC_CR2_HSI48RDY)) + ; + /* Enable peripheral clocks */ RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMAEN; RCC->APB2ENR |= RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_TIM15EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM17EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_SPI2EN | RCC_APB1ENR_USART3EN | - RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USBEN; + RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_SPI2EN | RCC_APB1ENR_USART3EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USBEN | RCC_APB1ENR_CRSEN; RCC->CFGR3 |= RCC_CFGR3_I2C1SW; + CRS->CR = CRS_CR_AUTOTRIMEN | CRS_CR_CEN; + #define AFRL(pin, val) ((val) << ((pin)*4)) #define AFRH(pin, val) ((val) << (((pin)-8)*4)) #define AF(pin) (2<<(2*(pin))) @@ -680,8 +927,15 @@ int main(void) { "LINE 3 LINE 3 LINE 3", "LINE 4 LINE 4 LINE 4"}; lcd_write_dma(lines); - led_init(); + + usbd_init(&usb_dev, &usbd_hw, USB_EP0_SIZE, usb_buf, sizeof(usb_buf)); + usbd_reg_config(&usb_dev, usb_setconf); + usbd_reg_control(&usb_dev, usb_control); + usbd_reg_descr(&usb_dev, usb_getdesc); + NVIC_EnableIRQ(USB_IRQn); + usbd_enable(&usb_dev, true); + usbd_connect(&usb_dev, true); // int apb2_clock = SystemCoreClock / APB2_PRESC; // // TIM15->PSC = apb2_clock / 1000000 * 100 - 1; /* 100us ticks */ @@ -729,6 +983,11 @@ void *memcpy(void *restrict dest, const void *restrict src, size_t n) return dest; } +void *memmove(void *dest, const void *src, size_t n) +{ + memcpy(dest, src, n); +} + void *memset(void *dest, int c, size_t n) { unsigned char *d = dest; diff --git a/upstream/libusb_stm32 b/upstream/libusb_stm32 new file mode 160000 index 0000000..9168e2a --- /dev/null +++ b/upstream/libusb_stm32 @@ -0,0 +1 @@ +Subproject commit 9168e2a31db946326fb84016a74ea2ab5bf87f54