USB CDC works
This commit is contained in:
parent
26bfcab3b4
commit
64b8097f34
4 changed files with 274 additions and 9 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "upstream/libusb_stm32"]
|
||||||
|
path = upstream/libusb_stm32
|
||||||
|
url = https://github.com/dmitrystu/libusb_stm32
|
||||||
6
Makefile
6
Makefile
|
|
@ -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)
|
||||||
|
|
|
||||||
265
src/main.c
265
src/main.c
|
|
@ -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
1
upstream/libusb_stm32
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9168e2a31db946326fb84016a74ea2ab5bf87f54
|
||||||
Loading…
Add table
Add a link
Reference in a new issue