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
|
||||
|
||||
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)
|
||||
|
|
|
|||
273
src/main.c
273
src/main.c
|
|
@ -2,6 +2,9 @@
|
|||
#include <global.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <usb.h>
|
||||
#include <usb_cdc.h>
|
||||
|
||||
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<<RCC_CFGR_MCO_Pos) | /* Forward 8 MHz HSI to MCO 1:1 */
|
||||
(4<<RCC_CFGR_PLLMUL_Pos) | /* Set PLL multiplier to 6x, leave divider at 1 */
|
||||
(1<<RCC_CFGR_PLLSRC_Pos) | /* Select HSI as PLL source */
|
||||
/* Leave HPRE at 1, not dividing clock. */
|
||||
(0<<RCC_CFGR_PPRE_Pos); /* Use SYSCLK for APB bus clock */
|
||||
(4<<RCC_CFGR_PLLMUL_Pos) | /* Set PLL multiplier to 6x, leave divider at 1 */
|
||||
(1<<RCC_CFGR_PLLSRC_Pos) | /* Select HSI as PLL source */
|
||||
/* Leave HPRE at 1, not dividing clock. */
|
||||
(0<<RCC_CFGR_PPRE_Pos); /* Use SYSCLK for APB bus clock */
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->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;
|
||||
|
|
|
|||
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