2 * Boiler System Bus Gateway
4 * (c) 2020 Martin Mareš <mj@ucw.cz>
10 #include <libopencm3/cm3/cortex.h>
11 #include <libopencm3/cm3/nvic.h>
12 #include <libopencm3/cm3/systick.h>
13 #include <libopencm3/cm3/scb.h>
14 #include <libopencm3/stm32/rcc.h>
15 #include <libopencm3/stm32/desig.h>
16 #include <libopencm3/stm32/gpio.h>
17 #include <libopencm3/stm32/timer.h>
18 #include <libopencm3/stm32/usart.h>
19 #include <libopencm3/usb/dfu.h>
20 #include <libopencm3/usb/usbd.h>
24 /*** Hardware init ***/
26 static void clock_init(void)
28 rcc_clock_setup_in_hse_8mhz_out_72mhz();
30 rcc_periph_clock_enable(RCC_GPIOA);
31 rcc_periph_clock_enable(RCC_GPIOB);
32 rcc_periph_clock_enable(RCC_GPIOC);
33 rcc_periph_clock_enable(RCC_USART1);
34 rcc_periph_clock_enable(RCC_USART3);
35 rcc_periph_clock_enable(RCC_USB);
37 rcc_periph_reset_pulse(RST_GPIOA);
38 rcc_periph_reset_pulse(RST_GPIOB);
39 rcc_periph_reset_pulse(RST_GPIOC);
40 rcc_periph_reset_pulse(RST_USART1);
41 rcc_periph_reset_pulse(RST_USART3);
42 rcc_periph_reset_pulse(RST_USB);
45 static void gpio_init(void)
47 // PA9 = TXD1 for debugging console
48 // PA10 = RXD1 for debugging console
49 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
50 gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
52 // PC13 = BluePill LED
53 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
54 gpio_clear(GPIOC, GPIO13);
56 // PB0 = yellow LED*, PB1 = green LED*
57 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0 | GPIO1);
58 gpio_set(GPIOB, GPIO0 | GPIO1);
60 // PB10 = TXD3 for BSB
61 // PB11 = RXD3 for BSB
62 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10);
63 gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11);
66 static void usart_init(void)
68 usart_set_baudrate(USART1, 115200);
69 usart_set_databits(USART1, 8);
70 usart_set_stopbits(USART1, USART_STOPBITS_1);
71 usart_set_mode(USART1, USART_MODE_TX);
72 usart_set_parity(USART1, USART_PARITY_NONE);
73 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
78 /*** System ticks ***/
80 static volatile u32 ms_ticks;
82 void sys_tick_handler(void)
87 static void tick_init(void)
89 systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
90 systick_counter_enable();
91 systick_interrupt_enable();
94 static void delay_ms(uint ms)
96 u32 start_ticks = ms_ticks;
97 while (ms_ticks - start_ticks < ms)
101 /*** Random generator ***/
103 static u32 rng_state;
105 static u32 random_u32(void)
107 rng_state *= 2654289733;
111 static void random_init(void)
114 desig_get_unique_id(desig);
115 rng_state = desig[0] ^ desig[1] ^ desig[2];
120 #define BSB_MAX_SIZE 32
121 #define BSB_RX_TIMEOUT 10 // ms
122 #define BSB_TX_IDLE_LINE 100 // ms
123 #define BSB_TX_MAX_ATTEMPTS 3
124 #define BSB_TX_WAIT_LOG 10 // base 2 log of timeout in ms
125 #define BSB_TX_TIMEOUT 10000 // ms
129 #define BSB_DEBUG(x) debug_putc(x)
131 #define BSB_DEBUG(x) do { } while (0)
135 byte rx_len; // Bytes received so far
136 byte rx_led; // Countdown to turning RX LED off
138 volatile u32 rx_timestamp; // Last byte received
140 byte tx_state; // TX_STATE_xxx
145 byte tx_result; // TX_RESULT_xxx
146 u32 tx_start_timestamp;
147 u32 tx_ticks_to_send;
149 byte rx_buf[BSB_MAX_SIZE];
150 byte tx_buf[BSB_MAX_SIZE];
153 static struct bsb_state bsb;
155 // Passing received frames and status codes to the main loop
156 static byte bsb_rx_frame[BSB_MAX_SIZE];
157 static volatile byte bsb_rx_frame_len;
158 static byte bsb_tx_result;
162 TX_STATE_WAITING_FOR_IDLE_LINE,
163 TX_STATE_PRE_PACKET_DELAY,
169 static struct bsb_stats bsb_stats;
171 static void bsb_attempt_tx(void);
173 static u16 bsb_crc_update(u16 crc, byte data)
175 crc = crc ^ (data << 8);
176 for (uint i=0; i<8; i++) {
178 crc = (crc << 1) ^ 0x1021;
185 void usart3_isr(void)
187 u32 status = USART_SR(USART3);
189 if (status & USART_SR_RXNE) {
190 uint ch = ~usart_recv(USART3) & 0xff;
191 bsb.rx_timestamp = ms_ticks;
193 debug_printf(" %02x", ch);
196 if (bsb.tx_state == TX_STATE_SENDING) {
197 // We are hearing the echo of a transmitted packet, check it for collisions
198 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
200 bsb.tx_state = TX_STATE_COLLISION;
201 } else if (ch == bsb.tx_buf[bsb.tx_check_index++]) {
202 if (bsb.tx_check_index >= bsb.tx_len) {
204 bsb.tx_state = TX_STATE_DONE;
208 bsb.tx_state = TX_STATE_COLLISION;
212 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
213 bsb_stats.rx_errors++;
215 } else if (!bsb.rx_len) {
218 bsb.rx_buf[bsb.rx_len++] = ch;
219 bsb.rx_crc = bsb_crc_update(0, ch);
222 bsb_stats.rx_noise++;
226 bsb.rx_buf[bsb.rx_len++] = ch;
227 bsb.rx_crc = bsb_crc_update(bsb.rx_crc, ch);
228 if (bsb.rx_len < 4) {
229 // First three bytes: SOF, source addr, destination addr
230 } else if (bsb.rx_len == 4) {
231 // Received length byte
232 if (bsb.rx_buf[3] < 7 || bsb.rx_buf[3] > BSB_MAX_SIZE) {
233 bsb_stats.rx_invalid++;
237 } else if (bsb.rx_len == bsb.rx_buf[3]) {
238 // Received a complete frame: check CRC and pass it to the main loop
240 bsb_stats.rx_bad_crc++;
243 if (bsb_rx_frame_len) {
244 // The previous one was not sent yet
245 bsb_stats.rx_overruns++;
248 memcpy(bsb_rx_frame, bsb.rx_buf, bsb.rx_buf[3]);
249 bsb_rx_frame_len = bsb.rx_buf[3] - 2;
253 gpio_clear(GPIOB, GPIO1);
262 if (status & USART_SR_TXE) {
263 if (bsb.tx_state == TX_STATE_SENDING && bsb.tx_send_index < bsb.tx_len) {
265 usart_send(USART3, bsb.tx_buf[bsb.tx_send_index++] ^ 0xff);
267 usart_disable_tx_interrupt(USART3);
268 // Main loop will be notified by receiving the echo of our frame,
269 // so we do not need to wait for the "transmit complete" flag.
274 static void bsb_rx_step(void)
276 cm_disable_interrupts();
278 if (bsb.rx_len && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
280 bsb_stats.rx_timeouts++;
285 gpio_set(GPIOB, GPIO1);
287 cm_enable_interrupts();
290 static void bsb_tx_step(void)
292 switch (bsb.tx_state) {
293 case TX_STATE_WAITING_FOR_IDLE_LINE:
294 if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE)
296 bsb.tx_state = TX_STATE_PRE_PACKET_DELAY;
299 case TX_STATE_PRE_PACKET_DELAY:
300 if (ms_ticks - bsb.tx_start_timestamp > BSB_TX_TIMEOUT) {
301 bsb.tx_state = TX_STATE_OFF;
302 bsb_tx_result = TX_RESULT_TIMEOUT;
303 bsb_stats.tx_timeouts++;
306 if (ms_ticks - bsb.rx_timestamp < BSB_TX_IDLE_LINE) {
307 bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
311 if (--bsb.tx_ticks_to_send)
314 bsb.rx_timestamp = ms_ticks;
316 bsb.tx_state = TX_STATE_SENDING;
318 usart_enable_tx_interrupt(USART3);
320 case TX_STATE_SENDING:
321 // In this state, we can race with the USART interrupt handler
322 cm_disable_interrupts();
323 if (bsb.tx_state == TX_STATE_SENDING && ms_ticks - bsb.rx_timestamp >= BSB_RX_TIMEOUT) {
324 // The echo of our packet was truncated due to collision
325 bsb.tx_state = TX_STATE_COLLISION;
328 cm_enable_interrupts();
330 case TX_STATE_COLLISION:
331 bsb_stats.tx_collisions++;
336 bsb.tx_state = TX_STATE_OFF;
337 bsb_tx_result = TX_RESULT_OK;
344 static void bsb_attempt_tx(void)
346 if (bsb.tx_attempts++ >= BSB_TX_MAX_ATTEMPTS) {
347 bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES;
348 bsb.tx_state = TX_STATE_OFF;
352 bsb.tx_ticks_to_send = (random_u32() | 0x80000000) >> (32 - BSB_TX_WAIT_LOG - (bsb.tx_attempts-1));
354 bsb.tx_state = TX_STATE_WAITING_FOR_IDLE_LINE;
355 bsb.tx_send_index = 0;
356 bsb.tx_check_index = 0;
357 debug_printf("TX: Attempt #%u, wait for %u ms\n", bsb.tx_attempts, (uint) bsb.tx_ticks_to_send);
360 static void bsb_send(byte *buf, uint len)
362 // If a transmit is in progress, declare overrrun
363 if (bsb_tx_result != TX_RESULT_NONE) {
364 bsb_stats.tx_overruns++;
367 if (bsb.tx_state != TX_STATE_OFF) {
368 bsb_stats.tx_overruns++;
369 bsb_tx_result = TX_RESULT_OVERRUN;
373 // Check frame validity
374 if (len < 5 || len > BSB_MAX_SIZE - 2 || buf[0] != 0xdc || buf[3] != len + 2) {
375 bsb_stats.tx_rejects++;
376 bsb_tx_result = TX_RESULT_MALFORMED;
380 // So far, we allow only QUERY frames from address 42
381 if (buf[1] != 0x80 + 42 && buf[4] != 0x06) {
382 bsb_stats.tx_rejects++;
383 bsb_tx_result = TX_RESULT_FORBIDDEN;
387 // Copy frame and calculate CRC
389 for (uint i=0; i<len; i++) {
390 bsb.tx_buf[i] = buf[i];
391 crc = bsb_crc_update(crc, buf[i]);
393 bsb.tx_buf[len++] = crc >> 8;
394 bsb.tx_buf[len++] = crc;
395 debug_printf("TX: Prepared frame of %u bytes with CRC %04x\n", len, crc);
397 // Queue frame for transmission
399 bsb.tx_start_timestamp = ms_ticks;
404 gpio_clear(GPIOB, GPIO0);
407 static void bsb_init(void)
409 usart_set_baudrate(USART3, 4800);
410 usart_set_databits(USART3, 9);
411 usart_set_stopbits(USART3, USART_STOPBITS_1);
412 usart_set_mode(USART3, USART_MODE_TX_RX);
413 usart_set_parity(USART3, USART_PARITY_ODD);
414 usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
416 usart_enable(USART3);
417 nvic_enable_irq(NVIC_USART3_IRQ);
418 usart_enable_rx_interrupt(USART3);
423 static usbd_device *usbd_dev;
425 static const struct usb_device_descriptor device = {
426 .bLength = USB_DT_DEVICE_SIZE,
427 .bDescriptorType = USB_DT_DEVICE,
429 .bDeviceClass = 0xFF,
430 .bDeviceSubClass = 0,
431 .bDeviceProtocol = 0,
432 .bMaxPacketSize0 = 64,
439 .bNumConfigurations = 1,
442 static const struct usb_endpoint_descriptor endpoints[] = {{
443 // Bulk end-point for sending frames to BSB
444 .bLength = USB_DT_ENDPOINT_SIZE,
445 .bDescriptorType = USB_DT_ENDPOINT,
446 .bEndpointAddress = 0x01,
447 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
448 .wMaxPacketSize = 64,
451 // Interrupt end-point for receiving frames from BSB
452 .bLength = USB_DT_ENDPOINT_SIZE,
453 .bDescriptorType = USB_DT_ENDPOINT,
454 .bEndpointAddress = 0x82,
455 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
456 .wMaxPacketSize = 64,
460 static const struct usb_interface_descriptor iface = {
461 .bLength = USB_DT_INTERFACE_SIZE,
462 .bDescriptorType = USB_DT_INTERFACE,
463 .bInterfaceNumber = 0,
464 .bAlternateSetting = 0,
466 .bInterfaceClass = 0xFF,
467 .bInterfaceSubClass = 0,
468 .bInterfaceProtocol = 0,
470 .endpoint = endpoints,
473 static const struct usb_dfu_descriptor dfu_function = {
474 .bLength = sizeof(struct usb_dfu_descriptor),
475 .bDescriptorType = DFU_FUNCTIONAL,
476 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
477 .wDetachTimeout = 255,
478 .wTransferSize = 1024,
479 .bcdDFUVersion = 0x0100,
482 static const struct usb_interface_descriptor dfu_iface = {
483 .bLength = USB_DT_INTERFACE_SIZE,
484 .bDescriptorType = USB_DT_INTERFACE,
485 .bInterfaceNumber = 1,
486 .bAlternateSetting = 0,
488 .bInterfaceClass = 0xFE,
489 .bInterfaceSubClass = 1,
490 .bInterfaceProtocol = 1,
493 .extra = &dfu_function,
494 .extralen = sizeof(dfu_function),
497 static const struct usb_interface ifaces[] = {{
499 .altsetting = &iface,
502 .altsetting = &dfu_iface,
505 static const struct usb_config_descriptor config = {
506 .bLength = USB_DT_CONFIGURATION_SIZE,
507 .bDescriptorType = USB_DT_CONFIGURATION,
510 .bConfigurationValue = 1,
512 .bmAttributes = 0x80,
513 .bMaxPower = 50, // multiplied by 2 mA
517 static char usb_serial_number[13];
519 static const char *usb_strings[] = {
520 "United Computer Wizards",
525 static byte usb_configured;
526 static byte usb_ep82_pending;
527 static uint8_t usbd_control_buffer[64];
529 static enum usbd_request_return_codes control_cb(
530 usbd_device *dev UNUSED,
531 struct usb_setup_data *req,
534 void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
536 if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
537 return USBD_REQ_NOTSUPP;
539 // We support reading of statistics via control requests
540 debug_printf("USB: Reading statistics\n");
541 uint n = MIN(*len, sizeof(bsb_stats));
542 memcpy(*buf, (char *) &bsb_stats, n);
545 return USBD_REQ_HANDLED;
548 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
550 // Reset to bootloader, which implements the rest of DFU
551 debug_printf("Switching to DFU\n");
556 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
557 struct usb_setup_data *req,
558 uint8_t **buf UNUSED,
559 uint16_t *len UNUSED,
560 void (**complete)(usbd_device *dev, struct usb_setup_data *req))
562 if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
563 return USBD_REQ_NOTSUPP;
565 *complete = dfu_detach_complete;
566 return USBD_REQ_HANDLED;
569 static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED)
571 // We received a frame from the USB host
573 uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf));
574 debug_printf("USB: Host sent %u bytes\n", len);
578 static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
580 // The frame was accepted by the USB host
581 debug_printf("USB: Interrupt done\n");
582 usb_ep82_pending = 0;
585 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
587 usbd_register_control_callback(
592 usbd_register_control_callback(
594 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
595 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
597 usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb);
598 usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 64, ep82_cb);
602 static void reset_cb(void)
604 debug_printf("USB: Reset\n");
606 usb_ep82_pending = 0;
609 static volatile bool usb_event_pending;
611 void usb_lp_can_rx0_isr(void)
614 * We handle USB in the main loop to avoid race conditions between
615 * USB interrupts and other code. However, we need an interrupt to
616 * up the main loop from sleep.
618 * We set up only the low-priority ISR, because high-priority ISR handles
619 * only double-buffered bulk transfers and isochronous transfers.
621 nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
622 usb_event_pending = 1;
625 static void usb_init(void)
627 // Simulate USB disconnect
628 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
629 gpio_clear(GPIOA, GPIO11 | GPIO12);
632 usbd_dev = usbd_init(
633 &st_usbfs_v1_usb_driver,
637 ARRAY_SIZE(usb_strings),
639 sizeof(usbd_control_buffer)
641 usbd_register_reset_callback(usbd_dev, reset_cb);
642 usbd_register_set_config_callback(usbd_dev, set_config_cb);
643 usb_event_pending = 1;
654 desig_get_unique_id_as_dfu(usb_serial_number);
657 debug_printf("Hail, Lord Damian! Thy BSB interface is ready.\n");
666 if (ms_ticks - last_blink >= 100) {
668 last_blink = ms_ticks;
671 if (usb_event_pending) {
673 usb_event_pending = 0;
674 nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
675 nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
678 if (usb_configured) {
679 // Passing of received frames to USB
680 if (!usb_ep82_pending) {
681 if (bsb_rx_frame_len) {
683 usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
684 usb_ep82_pending = 1;
686 bsb_rx_frame_len = 0;
687 debug_printf("USB: Sending frame to interrupt EP\n");
689 if (bsb_tx_result != TX_RESULT_NONE) {
690 usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1);
691 usb_ep82_pending = 1;
692 gpio_set(GPIOB, GPIO0); // Turn the TX LED off
693 debug_printf("USB: Sending status %u to interrupt EP\n", bsb_tx_result);
694 bsb_tx_result = TX_RESULT_NONE;
699 if (ms_ticks != last_step) {
700 last_step = ms_ticks;
705 wait_for_interrupt();