USB CDC works

This commit is contained in:
jaseg 2023-05-02 17:19:56 +02:00
parent 26bfcab3b4
commit 64b8097f34
4 changed files with 274 additions and 9 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "upstream/libusb_stm32"]
path = upstream/libusb_stm32
url = https://github.com/dmitrystu/libusb_stm32

View file

@ -30,7 +30,9 @@ DEVICE := STM32F072CB
ASM_SOURCES := startup.s 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 - CPP_SOURCES := # - none -
@ -83,7 +85,7 @@ COMMON_CFLAGS += -I$(abspath include)
COMMON_CFLAGS += -I$(BUILDDIR) COMMON_CFLAGS += -I$(BUILDDIR)
CFLAGS += -I$(abspath tools/musl_include_shims) 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 += -I$(CMSIS_DEVICE_DIR_ABS)/Include
CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS) CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS)

View file

@ -2,6 +2,9 @@
#include <global.h> #include <global.h>
#include <stdarg.h> #include <stdarg.h>
#include <usb.h>
#include <usb_cdc.h>
struct adc_state { struct adc_state {
uint8_t txbuf[12]; uint8_t txbuf[12];
uint8_t rxbuf[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) { int main(void) {
/* Enable HSE w/ 8 MHz crystal */ /* Enable HSE w/ 8 MHz crystal */
/* FIXME */ /* FIXME */
@ -571,13 +812,19 @@ int main(void) {
while (((RCC->CFGR & RCC_CFGR_SWS_Msk) >> RCC_CFGR_SWS_Pos) != 2) 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 */ /* Enable peripheral clocks */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMAEN; 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->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 |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_SPI2EN | RCC_APB1ENR_USART3EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USBEN | RCC_APB1ENR_CRSEN;
RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USBEN;
RCC->CFGR3 |= RCC_CFGR3_I2C1SW; RCC->CFGR3 |= RCC_CFGR3_I2C1SW;
CRS->CR = CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
#define AFRL(pin, val) ((val) << ((pin)*4)) #define AFRL(pin, val) ((val) << ((pin)*4))
#define AFRH(pin, val) ((val) << (((pin)-8)*4)) #define AFRH(pin, val) ((val) << (((pin)-8)*4))
#define AF(pin) (2<<(2*(pin))) #define AF(pin) (2<<(2*(pin)))
@ -680,8 +927,15 @@ int main(void) {
"LINE 3 LINE 3 LINE 3", "LINE 3 LINE 3 LINE 3",
"LINE 4 LINE 4 LINE 4"}; "LINE 4 LINE 4 LINE 4"};
lcd_write_dma(lines); lcd_write_dma(lines);
led_init(); 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; // int apb2_clock = SystemCoreClock / APB2_PRESC;
// //
// TIM15->PSC = apb2_clock / 1000000 * 100 - 1; /* 100us ticks */ // 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; 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) void *memset(void *dest, int c, size_t n)
{ {
unsigned char *d = dest; unsigned char *d = dest;

1
upstream/libusb_stm32 Submodule

@ -0,0 +1 @@
Subproject commit 9168e2a31db946326fb84016a74ea2ab5bf87f54