2 * Boiler System Bus Gateway
4 * (c) 2020 Martin Mareš <mj@ucw.cz>
9 #include <libopencm3/cm3/cortex.h>
10 #include <libopencm3/cm3/nvic.h>
11 #include <libopencm3/cm3/systick.h>
12 #include <libopencm3/cm3/scb.h>
13 #include <libopencm3/stm32/rcc.h>
14 #include <libopencm3/stm32/desig.h>
15 #include <libopencm3/stm32/gpio.h>
16 #include <libopencm3/stm32/timer.h>
17 #include <libopencm3/stm32/usart.h>
18 #include <libopencm3/usb/dfu.h>
19 #include <libopencm3/usb/usbd.h>
23 /*** Hardware init ***/
25 static void clock_init(void)
27 rcc_clock_setup_in_hse_8mhz_out_72mhz();
29 rcc_periph_clock_enable(RCC_GPIOA);
30 rcc_periph_clock_enable(RCC_GPIOB);
31 rcc_periph_clock_enable(RCC_GPIOC);
32 rcc_periph_clock_enable(RCC_USART1);
33 rcc_periph_clock_enable(RCC_USART3);
34 rcc_periph_clock_enable(RCC_USB);
36 rcc_periph_reset_pulse(RST_GPIOA);
37 rcc_periph_reset_pulse(RST_GPIOB);
38 rcc_periph_reset_pulse(RST_GPIOC);
39 rcc_periph_reset_pulse(RST_USART1);
40 rcc_periph_reset_pulse(RST_USART3);
41 rcc_periph_reset_pulse(RST_USB);
44 static void gpio_init(void)
46 // PA9 = TXD1 for debugging console
47 // PA10 = RXD1 for debugging console
48 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
49 gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
51 // PC13 = BluePill LED
52 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
53 gpio_clear(GPIOC, GPIO13);
55 // PB0 = yellow LED*, PB1 = green LED*
56 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0 | GPIO1);
57 gpio_set(GPIOB, GPIO0 | GPIO1);
59 // PB10 = TXD3 for BSB
60 // PB11 = RXD3 for BSB
61 // FIXME: TX turned off temporarily
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_RX);
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)
103 #define BSB_MAX_SIZE 32
104 #define BSB_RX_TIMEOUT 10 // ms
108 #define BSB_DEBUG(x...) debug_printf(x)
110 #define BSB_DEBUG(x...) do { } while (0)
113 static byte bsb_rx_buf[BSB_MAX_SIZE];
114 static byte bsb_rx_len;
115 static u16 bsb_rx_crc;
116 static volatile u32 bsb_rx_timestamp;
118 // Passing received frames to the main loop
119 static byte bsb_rx_frame[BSB_MAX_SIZE];
120 static volatile byte bsb_rx_frame_len;
121 static byte bsb_rx_frame_led;
133 static struct bsb_stat bsb_stat;
135 static u16 bsb_crc_update(u16 crc, byte data)
137 crc = crc ^ (data << 8);
138 for (uint i=0; i<8; i++) {
140 crc = (crc << 1) ^ 0x1021;
147 void usart3_isr(void)
149 u32 status = USART_SR(USART3);
151 if (status & USART_SR_RXNE) {
152 uint ch = ~usart_recv(USART3) & 0xff;
153 bsb_rx_timestamp = ms_ticks;
154 BSB_DEBUG(" %02x", ch);
156 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
157 bsb_stat.rx_errors++;
159 } else if (!bsb_rx_len) {
162 bsb_rx_buf[bsb_rx_len++] = ch;
163 bsb_rx_crc = bsb_crc_update(0, ch);
170 bsb_rx_buf[bsb_rx_len++] = ch;
171 bsb_rx_crc = bsb_crc_update(bsb_rx_crc, ch);
172 if (bsb_rx_len < 4) {
173 // First three bytes: SOF, source addr, destination addr
174 } else if (bsb_rx_len == 4) {
175 // Received length byte
176 if (bsb_rx_buf[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) {
177 bsb_stat.rx_invalid++;
181 } else if (bsb_rx_len == bsb_rx_buf[3]) {
182 // Received a complete frame: check CRC and pass it to the main loop
184 bsb_stat.rx_bad_crc++;
187 if (bsb_rx_frame_len) {
188 // The previous one was not sent yet
189 bsb_stat.rx_overruns++;
192 memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
193 bsb_rx_frame_len = bsb_rx_buf[3];
197 gpio_clear(GPIOB, GPIO1);
198 bsb_rx_frame_led = 100;
206 static void bsb_init(void)
208 usart_set_baudrate(USART3, 4800);
209 usart_set_databits(USART3, 9);
210 usart_set_stopbits(USART3, USART_STOPBITS_1);
211 usart_set_mode(USART3, USART_MODE_RX);
212 usart_set_parity(USART3, USART_PARITY_ODD);
213 usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
215 usart_enable(USART3);
216 nvic_enable_irq(NVIC_USART3_IRQ);
217 usart_enable_rx_interrupt(USART3);
222 static usbd_device *usbd_dev;
224 static const struct usb_device_descriptor device = {
225 .bLength = USB_DT_DEVICE_SIZE,
226 .bDescriptorType = USB_DT_DEVICE,
228 .bDeviceClass = 0xFF,
229 .bDeviceSubClass = 0,
230 .bDeviceProtocol = 0,
231 .bMaxPacketSize0 = 64,
238 .bNumConfigurations = 1,
241 static const struct usb_endpoint_descriptor endpoints[] = {{
242 .bLength = USB_DT_ENDPOINT_SIZE,
243 .bDescriptorType = USB_DT_ENDPOINT,
244 .bEndpointAddress = 0x81,
245 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
246 .wMaxPacketSize = 64,
249 .bLength = USB_DT_ENDPOINT_SIZE,
250 .bDescriptorType = USB_DT_ENDPOINT,
251 .bEndpointAddress = 0x82,
252 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
253 .wMaxPacketSize = 64,
257 static const struct usb_interface_descriptor iface = {
258 .bLength = USB_DT_INTERFACE_SIZE,
259 .bDescriptorType = USB_DT_INTERFACE,
260 .bInterfaceNumber = 0,
261 .bAlternateSetting = 0,
263 .bInterfaceClass = 0xFF,
264 .bInterfaceSubClass = 0,
265 .bInterfaceProtocol = 0,
267 .endpoint = endpoints,
270 static const struct usb_dfu_descriptor dfu_function = {
271 .bLength = sizeof(struct usb_dfu_descriptor),
272 .bDescriptorType = DFU_FUNCTIONAL,
273 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
274 .wDetachTimeout = 255,
275 .wTransferSize = 1024,
276 .bcdDFUVersion = 0x0100,
279 static const struct usb_interface_descriptor dfu_iface = {
280 .bLength = USB_DT_INTERFACE_SIZE,
281 .bDescriptorType = USB_DT_INTERFACE,
282 .bInterfaceNumber = 1,
283 .bAlternateSetting = 0,
285 .bInterfaceClass = 0xFE,
286 .bInterfaceSubClass = 1,
287 .bInterfaceProtocol = 1,
290 .extra = &dfu_function,
291 .extralen = sizeof(dfu_function),
294 static const struct usb_interface ifaces[] = {{
296 .altsetting = &iface,
299 .altsetting = &dfu_iface,
302 static const struct usb_config_descriptor config = {
303 .bLength = USB_DT_CONFIGURATION_SIZE,
304 .bDescriptorType = USB_DT_CONFIGURATION,
307 .bConfigurationValue = 1,
309 .bmAttributes = 0x80,
310 .bMaxPower = 50, // multiplied by 2 mA
314 static char usb_serial_number[13];
316 static const char *usb_strings[] = {
317 "United Computer Wizards",
322 static byte usb_configured;
323 static byte usb_rx_pending;
324 static uint8_t usbd_control_buffer[64];
326 static enum usbd_request_return_codes control_cb(
327 usbd_device *dev UNUSED,
328 struct usb_setup_data *req,
331 void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
333 if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
334 return USBD_REQ_NOTSUPP;
336 // We support reading of statistics via control requests
337 debug_printf("USB: Reading statistics\n");
338 uint n = MIN(*len, sizeof(bsb_stat));
339 memcpy(*buf, (char *) &bsb_stat, n);
342 return USBD_REQ_HANDLED;
345 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
347 // Reset to bootloader, which implements the rest of DFU
348 debug_printf("Switching to DFU\n");
353 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
354 struct usb_setup_data *req,
355 uint8_t **buf UNUSED,
356 uint16_t *len UNUSED,
357 void (**complete)(usbd_device *dev, struct usb_setup_data *req))
359 if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
360 return USBD_REQ_NOTSUPP;
362 *complete = dfu_detach_complete;
363 return USBD_REQ_HANDLED;
366 static void ep81_cb(usbd_device *dev, uint8_t ep UNUSED)
369 put_u32_be(buf, ms_ticks);
370 usbd_ep_write_packet(dev, 0x81, buf, sizeof(buf));
371 debug_printf("USB: Bulk write\n");
374 static void rx_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
376 // Received packet passed through interrupt end-point
377 debug_printf("USB: RX EP done\n");
381 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
383 usbd_register_control_callback(dev,
387 usbd_register_control_callback(dev,
388 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
389 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
391 usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb);
392 usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, rx_cb);
397 static void reset_cb(void)
399 debug_printf("USB: Reset\n");
403 static volatile bool usb_event_pending;
405 void usb_lp_can_rx0_isr(void)
408 * We handle USB in the main loop to avoid race conditions between
409 * USB interrupts and other code. However, we need an interrupt to
410 * up the main loop from sleep.
412 * We set up only the low-priority ISR, because high-priority ISR handles
413 * only double-buffered bulk transfers and isochronous transfers.
415 nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
416 usb_event_pending = 1;
419 static void usb_init(void)
421 // Simulate USB disconnect
422 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
423 gpio_clear(GPIOA, GPIO11 | GPIO12);
426 usbd_dev = usbd_init(
427 &st_usbfs_v1_usb_driver,
431 ARRAY_SIZE(usb_strings),
433 sizeof(usbd_control_buffer)
435 usbd_register_reset_callback(usbd_dev, reset_cb);
436 usbd_register_set_config_callback(usbd_dev, set_config_cb);
437 usb_event_pending = 1;
448 desig_get_unique_id_as_dfu(usb_serial_number);
450 debug_printf("Hello, kitty!\n");
455 u32 last_ds_step = 0;
458 if (ms_ticks - last_ds_step >= 100) {
460 gpio_toggle(GPIOB, GPIO0);
461 last_ds_step = ms_ticks;
464 if (usb_event_pending) {
466 usb_event_pending = 0;
467 nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
468 nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
471 if (usb_configured) {
472 // Passing of received packets to USB
473 if (!usb_rx_pending) {
474 if (bsb_rx_frame_len) {
476 usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
479 bsb_rx_frame_len = 0;
480 debug_printf("USB: RX started\n");
486 cm_disable_interrupts();
488 if (bsb_rx_len && ms_ticks - bsb_rx_timestamp >= BSB_RX_TIMEOUT) {
490 bsb_stat.rx_timeouts++;
493 if (bsb_rx_frame_led) {
494 if (!--bsb_rx_frame_led)
495 gpio_set(GPIOB, GPIO1);
497 cm_enable_interrupts();
499 wait_for_interrupt();