From cbb4ac1178362f61f854fd13f46ee0138c5d73ba Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 30 Aug 2020 15:27:11 +0200 Subject: make usb work with weird opencm3 hybrid --- Makefile | 10 ++- base.c | 10 +++ cdcacm.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 25 ++++--- 4 files changed, 291 insertions(+), 12 deletions(-) create mode 100644 cdcacm.c diff --git a/Makefile b/Makefile index b56e124..79cd8a6 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ # along with this program. If not, see . CUBE_PATH ?= $(wildcard ~)/resource/STM32CubeF1 +OPENCM3_PATH ?= $(wildcard ~)/resource/libopencm3 CMSIS_PATH ?= $(CUBE_PATH)/Drivers/CMSIS CMSIS_DEV_PATH ?= $(CMSIS_PATH)/Device/ST/STM32F1xx HAL_PATH ?= $(CUBE_PATH)/Drivers/STM32F1xx_HAL_Driver @@ -33,7 +34,8 @@ LDFLAGS = -nostdlib #LDFLAGS += -specs=rdimon.specs -DSEMIHOSTING LDFLAGS += -Wl,-Map=main.map #LDFLAGS += -Wl,--gc-sections -LIBS = -lm -lgcc +CFLAGS += -I$(OPENCM3_PATH)/include -L$(OPENCM3_PATH)/lib -DSTM32F1 +LIBS = -lm -lgcc -lopencm3_stm32f1 #LIBS += -lrdimon CFLAGS += -DSTM32F103xB -DHSE_VALUE=8000000 -DLSE_VALUE=32768 @@ -43,6 +45,8 @@ LDFLAGS += -Tstm32_flash.ld CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused -I../common LIBS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM3l_math +SOURCES = cdcacm.c main.c color.c + ################################################### .PHONY: program clean @@ -60,7 +64,7 @@ cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f103xb.h $(CMSIS_PATH)/Include/c $(CC) -c $(CFLAGS) -o $@ $^ # $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ -sources.tar.xz: main.c color.c Makefile +sources.tar.xz: $(SOURCES) Makefile tar -caf $@ $^ # don't ask... @@ -70,7 +74,7 @@ sources.tar.xz.zip: sources.tar.xz sources.c: sources.tar.xz.zip xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@ -main.elf: main.c color.c startup_stm32f103xb.s system_stm32f1xx.c $(HAL_PATH)/Src/stm32f1xx_ll_utils.c base.c cmsis_exports.c +main.elf: $(SOURCES) startup_stm32f103xb.s system_stm32f1xx.c $(HAL_PATH)/Src/stm32f1xx_ll_utils.c base.c cmsis_exports.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) $(OBJCOPY) -O binary $@ $(@:.elf=.bin) diff --git a/base.c b/base.c index 8e7c03b..8d095be 100644 --- a/base.c +++ b/base.c @@ -15,6 +15,16 @@ void *memset(void *s, int c, size_t n) { return s; } +void *memcpy(void *dest, const void *src, size_t n) { + uint8_t *out = (uint8_t *)dest; + const uint8_t *in = (const uint8_t *)src; + + while (n--) + *out++ = *in++; + + return dest; +} + size_t strlen(const char *s) { const char *start = s; while (*s++); diff --git a/cdcacm.c b/cdcacm.c new file mode 100644 index 0000000..5dc2ad0 --- /dev/null +++ b/cdcacm.c @@ -0,0 +1,258 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x2344, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* + * This notification endpoint isn't implemented. According to CDC spec its + * optional, but its absence causes a NULL pointer dereference in Linux + * cdc_acm driver. + */ +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof(cdcacm_functional_descriptors) +}}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, +}, { + .num_altsetting = 1, + .altsetting = data_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "jaseg.de", + "MoaRGB High Power RGB LED controller", + "a01-00000001", +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + (void)complete; + (void)buf; + (void)usbd_dev; + + switch(req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + char local_buf[10]; + struct usb_cdc_notification *notif = (void *)local_buf; + + /* We echo signals back to host as notification. */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + local_buf[8] = req->wValue & 3; + local_buf[9] = 0; + // usbd_ep_write_packet(0x83, buf, 10); + return USBD_REQ_HANDLED; + } + case USB_CDC_REQ_SET_LINE_CODING: + if(*len < sizeof(struct usb_cdc_line_coding)) + return USBD_REQ_NOTSUPP; + + return USBD_REQ_HANDLED; + } + return USBD_REQ_NOTSUPP; +} + +static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) +{ + (void)ep; + + char buf[64]; + int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); + + if (len) { + usbd_ep_write_packet(usbd_dev, 0x82, buf, len); + buf[len] = 0; + } +} + +static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) +{ + (void)wValue; + + usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +static usbd_device *usbd_dev; + +void usb_serial_init(void) +{ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_AFIO); + + AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON; + + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15); + + usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, cdcacm_set_config); + + gpio_set(GPIOA, GPIO15); + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15); +} + +void usb_serial_poll(void) +{ + usbd_poll(usbd_dev); +} + diff --git a/main.c b/main.c index 313bb7c..c87fa93 100644 --- a/main.c +++ b/main.c @@ -19,6 +19,9 @@ #include "math.h" #include "color.h" +extern void usb_serial_poll(void); +extern void usb_serial_init(void); + static struct hsvf g_color_s = {0.0f, 0.0f, 0.0f}; struct hsvf *g_color = &g_color_s; volatile uint64_t g_time_ms = 0; @@ -44,6 +47,9 @@ uint32_t pcg32_random_r() { } int main(void){ + /* This also sets the clocks */ + usb_serial_init(); + /* We're starting out from HSI@8MHz */ SystemCoreClockUpdate(); SysTick_Config(SystemCoreClock / 1000); /* 1ms tick */ @@ -89,18 +95,19 @@ int main(void){ uint64_t ts = g_time_ms; uint64_t led_ts = 0; for (;;) { - g_color->h = fmodf(g_color->h + 0.0005, 1.0f); - //g_color->h = 0.0; - g_color->s = 0.8; - g_color->v = 1.0; - - struct rgbf rgb; - hsv_to_rgb(g_color, &rgb); - update_timers(&rgb); + if (check_interval(&ts, 5)) { + g_color->h = fmodf(g_color->h + 0.0005, 1.0f); + //g_color->h = 0.0; + g_color->s = 0.8; + g_color->v = 1.0; - ts = wait_until(ts + 5); + struct rgbf rgb; + hsv_to_rgb(g_color, &rgb); + update_timers(&rgb); + } blink_led(&led_ts, 100, 200, GPIOC, 13); + usb_serial_poll(); } } -- cgit