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_USB);
35 rcc_periph_reset_pulse(RST_GPIOA);
36 rcc_periph_reset_pulse(RST_GPIOB);
37 rcc_periph_reset_pulse(RST_GPIOC);
38 rcc_periph_reset_pulse(RST_USART1);
39 rcc_periph_reset_pulse(RST_USB);
42 static void gpio_init(void)
44 // PA9 = TXD1 for debugging console
45 // PA10 = RXD1 for debugging console
46 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
47 gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
49 // PC13 = BluePill LED
50 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
51 gpio_clear(GPIOC, GPIO13);
53 // PB0 = yellow LED*, PB1 = green LED*
54 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO0 | GPIO1);
55 gpio_set(GPIOB, GPIO0 | GPIO1);
57 // PB10 = TXD3 for BSB
58 // PB11 = RXD3 for BSB
59 // FIXME: TX turned off temporarily
60 // gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10);
61 gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11);
64 static void usart_init(void)
66 usart_set_baudrate(USART1, 115200);
67 usart_set_databits(USART1, 8);
68 usart_set_stopbits(USART1, USART_STOPBITS_1);
69 usart_set_mode(USART1, USART_MODE_TX_RX);
70 usart_set_parity(USART1, USART_PARITY_NONE);
71 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
76 /*** System ticks ***/
78 static volatile u32 ms_ticks;
80 void sys_tick_handler(void)
85 static void tick_init(void)
87 systick_set_frequency(1000, 72000000);
88 systick_counter_enable();
89 systick_interrupt_enable();
92 static void delay_ms(uint ms)
94 u32 start_ticks = ms_ticks;
95 while (ms_ticks - start_ticks < ms)
101 #define BSB_MAX_SIZE 32
102 #define BSB_RX_TIMEOUT 2 // 1-2 ms => 2-4 byte periods of silence
104 static byte bsb_rx_buf[BSB_MAX_SIZE];
105 static byte bsb_rx_len;
106 static volatile u32 bsb_rx_timestamp;
108 // Passing received frames to the main loop
109 static byte bsb_rx_frame[BSB_MAX_SIZE];
110 static volatile byte bsb_rx_frame_len;
120 static struct bsb_stat bsb_stat;
122 void usart3_isr(void)
124 u32 status = USART_SR(USART3);
126 if (status & USART_SR_RXNE) {
127 uint ch = usart_recv(USART3);
128 bsb_rx_timestamp = ms_ticks;
130 if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
131 bsb_stat.rx_errors++;
133 } else if (!bsb_rx_len && ch != 0xdc) {
134 // Waiting for start of frame
137 bsb_rx_buf[bsb_rx_len++] = ch;
138 if (bsb_rx_len < 4) {
139 // First three bytes: SOF, source addr, destination addr
140 } else if (bsb_rx_len == 4) {
141 // Received length byte
142 if (bsb_rx_buf[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) {
143 bsb_stat.rx_invalid++;
146 } else if (bsb_rx_len == bsb_rx_buf[3]) {
147 // Received a complete frame: pass it to the main loop
148 if (bsb_rx_frame_len) {
149 // The previous one was not sent yet
150 bsb_stat.rx_overruns++;
152 memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
154 bsb_rx_frame_len = bsb_rx_buf[3];
161 static void bsb_init(void)
163 usart_set_baudrate(USART3, 4800);
164 usart_set_databits(USART3, 9);
165 usart_set_stopbits(USART3, USART_STOPBITS_1);
166 usart_set_mode(USART3, USART_MODE_TX_RX);
167 usart_set_parity(USART3, USART_PARITY_ODD);
168 usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
170 usart_enable(USART3);
171 nvic_enable_irq(NVIC_USART3_IRQ);
172 usart_enable_rx_interrupt(USART3);
177 static usbd_device *usbd_dev;
179 static const struct usb_device_descriptor device = {
180 .bLength = USB_DT_DEVICE_SIZE,
181 .bDescriptorType = USB_DT_DEVICE,
183 .bDeviceClass = 0xFF,
184 .bDeviceSubClass = 0,
185 .bDeviceProtocol = 0,
186 .bMaxPacketSize0 = 64,
193 .bNumConfigurations = 1,
196 static const struct usb_endpoint_descriptor endpoints[] = {{
197 .bLength = USB_DT_ENDPOINT_SIZE,
198 .bDescriptorType = USB_DT_ENDPOINT,
199 .bEndpointAddress = 0x81,
200 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
201 .wMaxPacketSize = 64,
204 .bLength = USB_DT_ENDPOINT_SIZE,
205 .bDescriptorType = USB_DT_ENDPOINT,
206 .bEndpointAddress = 0x82,
207 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
208 .wMaxPacketSize = 64,
212 static const struct usb_interface_descriptor iface = {
213 .bLength = USB_DT_INTERFACE_SIZE,
214 .bDescriptorType = USB_DT_INTERFACE,
215 .bInterfaceNumber = 0,
216 .bAlternateSetting = 0,
218 .bInterfaceClass = 0xFF,
219 .bInterfaceSubClass = 0,
220 .bInterfaceProtocol = 0,
222 .endpoint = endpoints,
225 static const struct usb_dfu_descriptor dfu_function = {
226 .bLength = sizeof(struct usb_dfu_descriptor),
227 .bDescriptorType = DFU_FUNCTIONAL,
228 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
229 .wDetachTimeout = 255,
230 .wTransferSize = 1024,
231 .bcdDFUVersion = 0x0100,
234 static const struct usb_interface_descriptor dfu_iface = {
235 .bLength = USB_DT_INTERFACE_SIZE,
236 .bDescriptorType = USB_DT_INTERFACE,
237 .bInterfaceNumber = 1,
238 .bAlternateSetting = 0,
240 .bInterfaceClass = 0xFE,
241 .bInterfaceSubClass = 1,
242 .bInterfaceProtocol = 1,
245 .extra = &dfu_function,
246 .extralen = sizeof(dfu_function),
249 static const struct usb_interface ifaces[] = {{
251 .altsetting = &iface,
254 .altsetting = &dfu_iface,
257 static const struct usb_config_descriptor config = {
258 .bLength = USB_DT_CONFIGURATION_SIZE,
259 .bDescriptorType = USB_DT_CONFIGURATION,
262 .bConfigurationValue = 1,
264 .bmAttributes = 0x80,
265 .bMaxPower = 50, // multiplied by 2 mA
269 static char usb_serial_number[13];
271 static const char *usb_strings[] = {
272 "United Computer Wizards",
277 static byte usb_configured;
278 static byte usb_rx_pending;
279 static uint8_t usbd_control_buffer[64];
281 static enum usbd_request_return_codes control_cb(
282 usbd_device *dev UNUSED,
283 struct usb_setup_data *req,
286 void (**complete)(usbd_device *dev, struct usb_setup_data *req) UNUSED)
288 if (req->bmRequestType != 0xc0 || req->bRequest != 0x00)
289 return USBD_REQ_NOTSUPP;
291 // We support reading of statistics via control requests
292 debug_printf("USB: Control request: Read statistics\n");
293 uint n = MIN(*len, sizeof(bsb_stat));
294 memcpy(*buf, (char *) &bsb_stat, n);
297 return USBD_REQ_HANDLED;
300 static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED)
302 // Reset to bootloader, which implements the rest of DFU
303 debug_printf("Switching to DFU\n");
308 static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED,
309 struct usb_setup_data *req,
310 uint8_t **buf UNUSED,
311 uint16_t *len UNUSED,
312 void (**complete)(usbd_device *dev, struct usb_setup_data *req))
314 if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH)
315 return USBD_REQ_NOTSUPP;
317 *complete = dfu_detach_complete;
318 return USBD_REQ_HANDLED;
321 static void ep81_cb(usbd_device *dev, uint8_t ep UNUSED)
324 put_u32_be(buf, ms_ticks);
325 usbd_ep_write_packet(dev, 0x81, buf, sizeof(buf));
326 debug_printf("USB: Bulk write\n");
329 static void rx_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED)
331 // Received packet passed through interrupt end-point
332 debug_printf("USB: RX EP done\n");
336 static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED)
338 usbd_register_control_callback(dev,
342 usbd_register_control_callback(dev,
343 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
344 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
346 usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb);
347 usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, rx_cb);
352 static void reset_cb(void)
354 debug_printf("USB: Reset\n");
358 static volatile bool usb_event_pending;
360 void usb_lp_can_rx0_isr(void)
363 * We handle USB in the main loop to avoid race conditions between
364 * USB interrupts and other code. However, we need an interrupt to
365 * up the main loop from sleep.
367 * We set up only the low-priority ISR, because high-priority ISR handles
368 * only double-buffered bulk transfers and isochronous transfers.
370 nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
371 usb_event_pending = 1;
374 static void usb_init(void)
376 // Simulate USB disconnect
377 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
378 gpio_clear(GPIOA, GPIO11 | GPIO12);
381 usbd_dev = usbd_init(
382 &st_usbfs_v1_usb_driver,
386 ARRAY_SIZE(usb_strings),
388 sizeof(usbd_control_buffer)
390 usbd_register_reset_callback(usbd_dev, reset_cb);
391 usbd_register_set_config_callback(usbd_dev, set_config_cb);
392 usb_event_pending = 1;
403 desig_get_unique_id_as_dfu(usb_serial_number);
405 debug_printf("Hello, kitty!\n");
410 u32 last_ds_step = 0;
413 if (ms_ticks - last_ds_step >= 100) {
415 gpio_toggle(GPIOB, GPIO0);
416 last_ds_step = ms_ticks;
419 if (usb_event_pending) {
421 usb_event_pending = 0;
422 nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ);
423 nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
426 if (usb_configured) {
427 // Passing of received packets to USB
428 if (!usb_rx_pending) {
429 if (bsb_rx_frame_len) {
431 usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
434 bsb_rx_frame_len = 0;
435 debug_printf("USB: RX started\n");
441 cm_disable_interrupts();
443 if (bsb_rx_len && (bsb_rx_timestamp - ms_ticks) >= BSB_RX_TIMEOUT) {
445 bsb_stat.rx_timeouts++;
447 cm_enable_interrupts();
449 wait_for_interrupt();