From: Martin Mares Date: Sun, 23 Feb 2020 22:51:43 +0000 (+0100) Subject: BSB: First experiments with USB X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=a692aefc44560a674b2057c6166c9d6b673cf779;p=home-hw.git BSB: First experiments with USB --- diff --git a/bsb/README b/bsb/README new file mode 100644 index 0000000..1c6fcce --- /dev/null +++ b/bsb/README @@ -0,0 +1,30 @@ +Assignment of peripherals and pins +================================== + +USART1 debugging +USART3 BSB + + + Blue Pill pinout + +--------------------+ + | VBATT 3.3V | +BluePill LED | PC13 GND | + | PC14 5V | + | PC15 PB9 | + | PA0 PB8 | + | PA1 PB7 | + | PA2 PB6 | + | PA3 PB5 | + | PA4 PB4 | + | PA5 PB3 | + | PA6 PA15 | + | PA7 PA12 | +yellow LED* | PB0 PA11 | +green LED* | PB1 PA10 | RXD1 - debugging console +TXD3 - BSB | PB10 PA9 | TXD1 - debugging console +RXD3 - BSB | PB11 PA8 | + | RESET PB15 | + | 3.3 V PB14 | + | GND PB13 | + | GND PB12 | + +--------------------+ diff --git a/bsb/daemon/Makefile b/bsb/daemon/Makefile new file mode 100644 index 0000000..10ed633 --- /dev/null +++ b/bsb/daemon/Makefile @@ -0,0 +1,11 @@ +PC := pkg-config +USB_CFLAGS := $(shell $(PC) --cflags libusb-1.0) +USB_LDFLAGS := $(shell $(PC) --libs libusb-1.0) + +CFLAGS=$(USB_CFLAGS) $(CURL_CFLAGS) -std=gnu1x -O2 -Wall -Wextra -Wno-parentheses +LDFLAGS=$(USB_LDFLAGS) $(CURL_LDFLAGS) + +all: burrow-bsb + +clean: + rm -f burrow-bsb diff --git a/bsb/daemon/burrow-bsb.c b/bsb/daemon/burrow-bsb.c new file mode 100644 index 0000000..8150de2 --- /dev/null +++ b/bsb/daemon/burrow-bsb.c @@ -0,0 +1,137 @@ +/* + * Boiler System Bus Interface Daemon + * + * (c) 2020 Martin Mares + */ + +#include +#include +#include +#include +#include +#include + +#include + +static struct libusb_context *usb_ctxt; +static struct libusb_device_handle *devh; + +static void die(const char *msg, ...) +{ + va_list args; + va_start(args, msg); + + vfprintf(stderr, msg, args); + fputc('\n', stderr); + + exit(1); +} + +static void usb_error(const char *msg, ...) +{ + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + va_end(args); + + if (devh) { + libusb_close(devh); + devh = NULL; + } +} + +static void open_device(void) +{ + int err; + libusb_device **devlist; + ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist); + if (devn < 0) + die("Cannot enumerate USB devices: error %d", (int) devn); + + for (ssize_t i=0; i %02x%02x%02x%02x\n", resp[0], resp[1], resp[2], resp[3]); +#elif 0 + int received; + unsigned char resp[64]; + if (err = libusb_interrupt_transfer(devh, 0x82, resp, 64, &received, 100)) { + usb_error("Receive failed: error %d", err); + continue; + } + + printf("Interrupt received %d bytes\n", received); + if (received < 4) { + usb_error("Receive failed: unexpected response size %d", received); + continue; + } + + printf("-> %02x%02x%02x%02x\n", resp[0], resp[1], resp[2], resp[3]); +#else + unsigned char resp[64] = { 1, 2, 3, 4 }; + if ((err = libusb_control_transfer(devh, 0xc0, 0x00, 0, 0, resp, 4, 100)) < 0) { + usb_error("Receive failed: error %d", err); + continue; + } + + printf("-> %02x%02x%02x%02x\n", resp[0], resp[1], resp[2], resp[3]); +#endif + + sleep(1); + } +} diff --git a/bsb/firmware/Makefile b/bsb/firmware/Makefile new file mode 100644 index 0000000..e50d926 --- /dev/null +++ b/bsb/firmware/Makefile @@ -0,0 +1,6 @@ +ROOT=../.. +BINARY=bsb +OBJS=main.o +LIB_OBJS=util-debug.o + +include $(ROOT)/mk/bluepill.mk diff --git a/bsb/firmware/config.h b/bsb/firmware/config.h new file mode 100644 index 0000000..24b1b42 --- /dev/null +++ b/bsb/firmware/config.h @@ -0,0 +1,14 @@ +/* + * Burrow Clock -- Configuration + * + * (c) 2019 Martin Mareš + */ + +// Processor clock + +#define CPU_CLOCK_MHZ 72 + +// Debugging port + +#define DEBUG_USART USART1 +#define DEBUG_LED_BLUEPILL diff --git a/bsb/firmware/main.c b/bsb/firmware/main.c new file mode 100644 index 0000000..fda60d4 --- /dev/null +++ b/bsb/firmware/main.c @@ -0,0 +1,239 @@ +/* + * Boiler System Bus Gateway + * + * (c) 2020 Martin Mareš + */ + +#include "util.h" + +#include +#include +#include // FIXME: Clean up +#include +#include +#include +#include + +#include + +static void clock_init(void) +{ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_USART1); + rcc_periph_clock_enable(RCC_USB); + + rcc_periph_reset_pulse(RST_GPIOA); + rcc_periph_reset_pulse(RST_GPIOB); + rcc_periph_reset_pulse(RST_GPIOC); + rcc_periph_reset_pulse(RST_USART1); + rcc_periph_reset_pulse(RST_USB); +} + +static void gpio_init(void) +{ + // PA9 = TXD1 for debugging console + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9); + + // PA10 = RXD1 for debugging console + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10); + + // PC13 = BluePill LED + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13); + gpio_clear(GPIOC, GPIO13); +} + +static volatile u32 ms_ticks; + +void sys_tick_handler(void) +{ + ms_ticks++; +} + +static void tick_init(void) +{ + systick_set_frequency(1000, 72000000); + systick_counter_enable(); + systick_interrupt_enable(); +} + +static void delay_ms(uint ms) +{ + u32 start_ticks = ms_ticks; + while (ms_ticks - start_ticks < ms) + ; +} + +static void usart_init(void) +{ + usart_set_baudrate(USART1, 115200); + usart_set_databits(USART1, 8); + usart_set_stopbits(USART1, USART_STOPBITS_1); + usart_set_mode(USART1, USART_MODE_TX_RX); + usart_set_parity(USART1, USART_PARITY_NONE); + usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); + + usart_enable(USART1); +} + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0xFF, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x4242, + .idProduct = 0x0003, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +static const struct usb_endpoint_descriptor endpoints[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +},{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xFF, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = endpoints, +}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = &iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 50, // multiplied by 2 mA + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "United Computer Wizards", + "BSB Gateway", + "1", +}; + +static byte usb_configured; +static uint8_t usbd_control_buffer[64]; + +static enum usbd_request_return_codes control_cb(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) UNUSED) +{ + if (req->bmRequestType != 0xc0 || req->bRequest != 0x00) + return USBD_REQ_NOTSUPP; + + (void) usbd_dev; + (void) buf; + (void) len; + (void) complete; + debug_printf("USB: Control request\n"); + + byte *b = *buf; + b[0] = 0x12; + b[1] = 0x34; + b[2] = 0x56; + b[3] = 0x78; + if (*len > 4) + *len = 4; + + return USBD_REQ_HANDLED; +} + +static void ep81_cb(usbd_device *usbd_dev, uint8_t ep UNUSED) +{ + byte buf[4]; + put_u32_be(buf, ms_ticks); + usbd_ep_write_packet(usbd_dev, 0x81, buf, sizeof(buf)); + debug_printf("USB: Bulk write\n"); +} + +static void set_config_cb(usbd_device *usbd_dev, uint16_t wValue UNUSED) +{ + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, USB_REQ_TYPE_TYPE, control_cb); + usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + ep81_cb(usbd_dev, 0); + usb_configured = 1; +} + +static void reset_cb(void) +{ + debug_printf("USB: Reset\n"); + usb_configured = 0; +} + +int main(void) +{ + clock_init(); + gpio_init(); + tick_init(); + usart_init(); + + debug_printf("Hello, kitty!\n"); + + // Simulate USB disconnect + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12); + gpio_clear(GPIOA, GPIO11 | GPIO12); + delay_ms(1000); + + usbd_device *usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_reset_callback(usbd_dev, reset_cb); + usbd_register_set_config_callback(usbd_dev, set_config_cb); + u32 last_ds_step = 0; + + for (;;) { + if (ms_ticks - last_ds_step >= 100) { + debug_led_toggle(); + last_ds_step = ms_ticks; + if (usb_configured) { + byte x[4]; + put_u32_be(x, ms_ticks); + usbd_ep_write_packet(usbd_dev, 0x82, x, 4); + } + } + + // XXX: libopencm3 usbd does not use interrupts at the moment, need to poll... + // wait_for_interrupt(); + usbd_poll(usbd_dev); + } + + return 0; +}