]> mj.ucw.cz Git - home-hw.git/commitdiff
BSB: First experiments with USB
authorMartin Mares <mj@ucw.cz>
Sun, 23 Feb 2020 22:51:43 +0000 (23:51 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 23 Feb 2020 22:51:43 +0000 (23:51 +0100)
bsb/README [new file with mode: 0644]
bsb/daemon/Makefile [new file with mode: 0644]
bsb/daemon/burrow-bsb.c [new file with mode: 0644]
bsb/firmware/Makefile [new file with mode: 0644]
bsb/firmware/config.h [new file with mode: 0644]
bsb/firmware/main.c [new file with mode: 0644]

diff --git a/bsb/README b/bsb/README
new file mode 100644 (file)
index 0000000..1c6fcce
--- /dev/null
@@ -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 (file)
index 0000000..10ed633
--- /dev/null
@@ -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 (file)
index 0000000..8150de2
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *     Boiler System Bus Interface Daemon
+ *
+ *     (c) 2020 Martin Mares <mj@ucw.cz>
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libusb-1.0/libusb.h>
+
+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<devn; i++) {
+               struct libusb_device_descriptor desc;
+               libusb_device *dev = devlist[i];
+               if (!libusb_get_device_descriptor(dev, &desc)) {
+                       if (desc.idVendor == 0x4242 && desc.idProduct == 0x0003) {
+                               fprintf(stderr, "Found device at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+
+                               if (err = libusb_open(dev, &devh)) {
+                                       usb_error("Cannot open device: error %d", err);
+                                       goto out;
+                               }
+                               libusb_reset_device(devh);
+                               if (err = libusb_claim_interface(devh, 0)) {
+                                       usb_error("Cannot claim interface: error %d", err);
+                                       goto out;
+                               }
+
+                               goto out;
+                       }
+               }
+       }
+
+out:
+       libusb_free_device_list(devlist, 1);
+}
+
+int main(void)
+{
+       int err;
+       if (err = libusb_init(&usb_ctxt))
+               die("Cannot initialize libusb: error %d", err);
+       // libusb_set_debug(usb_ctxt, 3);
+       open_device();
+
+       for (;;) {
+               if (!devh) {
+                       fprintf(stderr, "Waiting for device to appear...\n");
+                       while (!devh) {
+                               sleep(5);
+                               open_device();
+                       }
+               }
+
+#if 0
+               int received;
+               unsigned char resp[64];
+               if (err = libusb_bulk_transfer(devh, 0x81, resp, 64, &received, 2000)) {
+                       usb_error("Receive failed: error %d", err);
+                       continue;
+               }
+
+               printf("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]);
+#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 (file)
index 0000000..e50d926
--- /dev/null
@@ -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 (file)
index 0000000..24b1b42
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *     Burrow Clock -- Configuration
+ *
+ *     (c) 2019 Martin Mareš <mj@ucw.cz>
+ */
+
+// 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 (file)
index 0000000..fda60d4
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ *     Boiler System Bus Gateway
+ *
+ *     (c) 2020 Martin Mareš <mj@ucw.cz>
+ */
+
+#include "util.h"
+
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/stm32/rcc.h>              // FIXME: Clean up
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/usb/usbd.h>
+
+#include <string.h>
+
+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;
+}