From b30057d812c9e14f2a9b9deb4116fe291f872642 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 14 May 2023 14:39:53 +0200 Subject: [PATCH] Clock: New firmware (formerly test-display2) --- clock/firmware/Makefile | 11 +- clock/firmware/README | 31 +++ clock/firmware/config.h | 8 +- clock/firmware/main.c | 561 +++++++++++++++++++++++++++++++++++----- 4 files changed, 544 insertions(+), 67 deletions(-) create mode 100644 clock/firmware/README diff --git a/clock/firmware/Makefile b/clock/firmware/Makefile index c54fa11..8063dfb 100644 --- a/clock/firmware/Makefile +++ b/clock/firmware/Makefile @@ -1,6 +1,11 @@ -ROOT=../.. -BINARY=clock +ROOT=.. +BINARY=test OBJS=main.o -LIB_OBJS=util-debug.o ds18b20.o +LIB_OBJS=util-debug.o + +WITH_BOOT_LOADER=1 +WITH_DFU_FLASH=1 +DFU_ARGS=-d 4242:0007 +# DFU_ARGS=-d 4242:0008 include $(ROOT)/mk/bluepill.mk diff --git a/clock/firmware/README b/clock/firmware/README new file mode 100644 index 0000000..f3700f6 --- /dev/null +++ b/clock/firmware/README @@ -0,0 +1,31 @@ +Assignment of peripherals and pins +================================== + +I2C1 display +USART1 debugging +TIM1 IR receiver + + + Blue Pill pinout + +--------------------+ + | VBATT 3.3V | +BluePill LED | PC13 GND | display power + | PC14 5V | display power (white side of connector) + | PC15 PB9 | + | PA0 PB8 | + | PA1 PB7 | SDA1 display (white side of connector) + | PA2 PB6 | SCL1 display + | PA3 PB5 | + | PA4 PB4 | + | PA5 PB3 | + | PA6 PA15 | + | PA7 PA12 | + | PB0 PA11 | + | PB1 PA10 | RXD1 - debugging console + | PB10 PA9 | TXD1 - debugging console + | PB11 PA8 | SFH5110 output (white side of connector) + | RESET PB15 | + | 3.3 V PB14 | + | GND PB13 | + | GND PB12 | + +--------------------+ diff --git a/clock/firmware/config.h b/clock/firmware/config.h index 24b1b42..50926f9 100644 --- a/clock/firmware/config.h +++ b/clock/firmware/config.h @@ -1,7 +1,7 @@ /* - * Burrow Clock -- Configuration + * Workshop Clock -- Configuration * - * (c) 2019 Martin Mareš + * (c) 2020-2023 Martin Mareš */ // Processor clock @@ -12,3 +12,7 @@ #define DEBUG_USART USART1 #define DEBUG_LED_BLUEPILL + +// Testing of IR receiver + +#undef IR_TEST diff --git a/clock/firmware/main.c b/clock/firmware/main.c index b2b7cc3..50ce567 100644 --- a/clock/firmware/main.c +++ b/clock/firmware/main.c @@ -1,53 +1,84 @@ /* - * Clock with Barometer + * Workshop Clock * - * (c) 2018--2019 Martin Mareš + * (c) 2020-2023 Martin Mareš */ -FIXME: Partial code... - #include "util.h" +#include #include #include +#include #include +#include #include -#include #include +#include +#include +#include +#include #include +static void ep82_send(u32 key_code); + +/*** Hardware init ***/ + static void clock_init(void) { - rcc_clock_setup_in_hse_8mhz_out_72mhz(); + rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); + rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_I2C1); rcc_periph_clock_enable(RCC_USART1); rcc_periph_clock_enable(RCC_USB); + rcc_periph_clock_enable(RCC_TIM1); + rcc_periph_reset_pulse(RST_GPIOA); rcc_periph_reset_pulse(RST_GPIOB); rcc_periph_reset_pulse(RST_GPIOC); + rcc_periph_reset_pulse(RST_I2C1); rcc_periph_reset_pulse(RST_USART1); rcc_periph_reset_pulse(RST_USB); + rcc_periph_reset_pulse(RST_TIM1); } static void gpio_init(void) { - // Switch JTAG off to free up pins - gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); - // 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_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9); 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); + + // PB7 = SDA for display controller + // PB6 = SCL for display controller + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO6 | GPIO7); + + // PA8 = SFH5110 output (5V tolerant) connected to TIM1_CH1 + gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO8); } +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); + usart_set_parity(USART1, USART_PARITY_NONE); + usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); + + usart_enable(USART1); +} + +/*** System ticks ***/ + static volatile u32 ms_ticks; void sys_tick_handler(void) @@ -57,33 +88,281 @@ void sys_tick_handler(void) static void tick_init(void) { - systick_set_frequency(1000, 72000000); + systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000); systick_counter_enable(); systick_interrupt_enable(); } -#if 0 static void delay_ms(uint ms) { u32 start_ticks = ms_ticks; while (ms_ticks - start_ticks < ms) ; } -#endif -static void usart_init(void) +/*** Display ***/ + +/* + * Display digits: + * + * ---- 40 ---- + * | | + * | | + * 20 80 + * | | + * | | + * ---- 10 ---- + * | | + * | | + * 08 02 + * | | + * | | + * ---- 04 ---- + * (01) + */ + +static byte disp[4]; +static byte ctrl = 0x56; + +static const byte disp_font[] = { + [0] = 0xee, + [1] = 0x82, + [2] = 0xdc, + [3] = 0xd6, + [4] = 0xb2, + [5] = 0x76, + [6] = 0x7e, + [7] = 0xc2, + [8] = 0xfe, + [9] = 0xf6, + [10] = 0xea, + [11] = 0x3e, + [12] = 0x6c, + [13] = 0x9e, + [14] = 0x7c, + [15] = 0x78, +}; + +static void display_update(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); + // debug_puts("Display update\n"); - usart_enable(USART1); + byte cmds[4]; + cmds[0] = 0; + cmds[1] = ctrl; + cmds[2] = ((disp[1] & 0x88) >> 3) | ((disp[1] & 0x44) >> 1) | ((disp[1] & 0x22) << 1) | ((disp[1] & 0x11) << 3); + cmds[3] = disp[0]; + i2c_transfer7(I2C1, 0x76/2, (byte *) cmds, sizeof(cmds), NULL, 0); + + cmds[2] = ((disp[3] & 0x88) >> 3) | ((disp[3] & 0x44) >> 1) | ((disp[3] & 0x22) << 1) | ((disp[3] & 0x11) << 3); + cmds[3] = disp[2]; + i2c_transfer7(I2C1, 0x70/2, (byte *) cmds, sizeof(cmds), NULL, 0); + + // debug_puts("Update done\n"); +} + +static void display_init(void) +{ + debug_puts("I2C init\n"); + i2c_peripheral_disable(I2C1); + i2c_set_speed(I2C1, i2c_speed_sm_100k, rcc_apb1_frequency / 1000000); + i2c_peripheral_enable(I2C1); + + disp[0] = 0x10; + disp[1] = 0x10; + disp[2] = 0x10; + disp[3] = 0x10; + display_update(); +} + +/*** Infrared Remote Control ***/ + +static void ir_init(void) +{ + debug_puts("IR init\n"); + + // TIM1 will measure pulses and spaces between them with 1μs resolution + timer_set_prescaler(TIM1, 71); // 72 MHz / 72 = 1 MHz + timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_set_period(TIM1, 65535); + timer_update_on_overflow(TIM1); + + // IC1 will trigger on TI1 (TIM1_CH1) falling edge + timer_ic_set_input(TIM1, TIM_IC1, TIM_IC_IN_TI1); + // timer_ic_set_filter(TIM1, TIM_IC1, TIM_IC_OFF); + timer_set_oc_polarity_low(TIM1, TIM_OC1); // OC functions affect IC, too + + // IC2 will trigger on TI1 (TIM1_CH1) rising edge + timer_ic_set_input(TIM1, TIM_IC2, TIM_IC_IN_TI1); + timer_set_oc_polarity_high(TIM1, TIM_OC2); + + // OC3 will trigger on a break longer than 50 ms + timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_ACTIVE); + timer_set_oc_value(TIM1, TIM_OC3, 30000); + + // Program slave controller to reset the timer on IC1 + timer_slave_set_trigger(TIM1, TIM_SMCR_TS_TI1FP1); + timer_slave_set_mode(TIM1, TIM_SMCR_SMS_RM); + + // Request interrupts + timer_enable_irq(TIM1, TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); + nvic_enable_irq(NVIC_TIM1_CC_IRQ); + + // Enable ICs and OCs + timer_enable_oc_output(TIM1, TIM_OC1); + timer_enable_oc_output(TIM1, TIM_OC2); + timer_enable_oc_output(TIM1, TIM_OC3); + + timer_enable_counter(TIM1); +} + +// Circular queue of pulse durations +#define IR_MAX_PULSES 32 +static u32 ir_pulses[IR_MAX_PULSES]; // Top 16 bits = mark, bottom 16 bits = space +static u16 ir_last_pulse; +static uint ir_pulses_rx, ir_pulses_tx; + +#define IR_INF 0xffff + +#define IR_MARK(x) (uint)((x) >> 16) +#define IR_SPACE(x) (uint)((x) & 0xffff) + +static inline bool between(uint x, uint min, uint max) +{ + return x >= min && x <= max; +} + +static void ir_record_pulse(uint mark, uint space) +{ + uint i = ir_pulses_tx; + ir_pulses_tx = (i + 1) % IR_MAX_PULSES; + if (ir_pulses_tx != ir_pulses_rx) { + ir_pulses[i] = (mark << 16) | space; + } else { + // Overflow detected + ir_pulses[i] = (IR_INF << 16) | IR_INF; + } +} + +void tim1_cc_isr(void) +{ + if (TIM_SR(TIM1) & TIM_SR_CC1IF) { + TIM_SR(TIM1) &= ~TIM_SR_CC1IF; + u16 now = TIM_CCR1(TIM1); + if (ir_last_pulse) { + ir_record_pulse(ir_last_pulse, now - ir_last_pulse); + ir_last_pulse = 0; + } + } + if (TIM_SR(TIM1) & TIM_SR_CC2IF) { + TIM_SR(TIM1) &= ~TIM_SR_CC2IF; + ir_last_pulse = TIM_CCR2(TIM1); + } + if (TIM_SR(TIM1) & TIM_SR_CC3IF) { + TIM_SR(TIM1) &= ~TIM_SR_CC3IF; + if (ir_last_pulse) { + ir_record_pulse(ir_last_pulse, IR_INF); + ir_last_pulse = 0; + } + } +} + +static u32 ir_get_pulse(void) +{ + u32 out = 0; + + cm_disable_interrupts(); + if (ir_pulses_rx != ir_pulses_tx) { + out = ir_pulses[ir_pulses_rx]; + ir_pulses_rx = (ir_pulses_rx + 1) % IR_MAX_PULSES; + } + cm_enable_interrupts(); + return out; +} + +// Decoder for Onkyo RC-748S + +static u32 ir_blink_start; + +static void ir_decode(void) +{ + u32 pulse = ir_get_pulse(); + if (!pulse) + return; + + uint mark = IR_MARK(pulse); + uint space = IR_SPACE(pulse); + +#ifdef IR_TEST + debug_printf("IR: %d %d\n", mark, space); + return; +#endif + + static u16 ir_bits; + static u32 ir_code; +#define IR_ERR 0xff + + // debug_printf("IR(%d): %d %d\n", ir_bits, mark, space); + + if (space == IR_INF) { + ir_bits = 0; + } else if (ir_bits == IR_ERR) { + // Error state + } else if (ir_bits == 0) { + // Start? + if (between(mark, 8900, 9200)) { + if (between(space, 4200, 4600)) { + ir_bits = 1; + ir_code = 0; + } else if (between(space, 2000, 2300)) { + debug_printf("IR: => REP\n"); + ir_bits = IR_ERR; + } + } + } else { + if (between(mark, 500, 700)) { + ir_bits++; + if (between(space, 400, 700)) { + // 0 + } else if (between(space, 1500, 1800)) { + // 1 + ir_code |= 1U << (33 - ir_bits); + } else { + ir_bits = IR_ERR; + } + if (ir_bits == 33) { + debug_printf("IR: => %08x\n", (uint)ir_code); + disp[3] |= 0x01; + ir_blink_start = ms_ticks; + display_update(); + ir_bits = IR_ERR; + ep82_send(ir_code); + } + } else { + ir_bits = IR_ERR; + } + } } -static const struct usb_device_descriptor dev = { +/*** USB ***/ + +static usbd_device *usbd_dev; + +enum usb_string { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIAL, +}; + +static char usb_serial_number[13]; + +static const char *usb_strings[] = { + "United Computer Wizards", + "Workshop Clock", + usb_serial_number, +}; + +static const struct usb_device_descriptor device = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = 0x0200, @@ -91,22 +370,31 @@ static const struct usb_device_descriptor dev = { .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = 0xCAFE, - .idProduct = 0xCAFE, - .bcdDevice = 0x0200, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, + .idVendor = 0x4242, + .idProduct = 0x0007, + .bcdDevice = 0x0000, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIAL, .bNumConfigurations = 1, }; static const struct usb_endpoint_descriptor endpoints[] = {{ + // Bulk end-point for sending values to the display .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x81, + .bEndpointAddress = 0x01, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 1, +}, { + // Bulk end-point for receiving remote control keys + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 4, + .bInterval = 1, }}; static const struct usb_interface_descriptor iface = { @@ -114,7 +402,7 @@ static const struct usb_interface_descriptor iface = { .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, - .bNumEndpoints = 1, + .bNumEndpoints = 2, .bInterfaceClass = 0xFF, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, @@ -122,16 +410,43 @@ static const struct usb_interface_descriptor iface = { .endpoint = endpoints, }; +static const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof(struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x0100, +}; + +static const struct usb_interface_descriptor dfu_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = 0, + + .extra = &dfu_function, + .extralen = sizeof(dfu_function), +}; + static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, .altsetting = &iface, +}, { + .num_altsetting = 1, + .altsetting = &dfu_iface, }}; static const struct usb_config_descriptor config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, - .bNumInterfaces = 1, + .bNumInterfaces = 2, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, @@ -139,57 +454,179 @@ static const struct usb_config_descriptor config = { .interface = ifaces, }; -static const char *usb_strings[] = { - "Hippo Computing Inc.", - "Space Alert Thermometer", - "42", -}; +static bool usb_configured; +static uint8_t usbd_control_buffer[64]; + +static bool usb_tx_in_flight; +static byte ep82_tx_buffer[4]; -uint8_t usbd_control_buffer[64]; +static byte disp_alive; -static void ep81_cb(usbd_device *usbd_dev, uint8_t ep UNUSED) +static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED) { - byte buf[4]; - if (ds_sensors[0].address[0] && ds_sensors[0].current_temp != DS_TEMP_UNKNOWN) { - put_u32_be(buf, (u32) ds_sensors[0].current_temp); - } else { - put_u32_be(buf, 0x80000000); + // Reset to bootloader, which implements the rest of DFU + debug_printf("Switching to DFU\n"); + debug_flush(); + scb_reset_core(); +} + +static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED, + struct usb_setup_data *req, + uint8_t **buf UNUSED, + uint16_t *len UNUSED, + void (**complete)(usbd_device *dev, struct usb_setup_data *req)) +{ + if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH) + return USBD_REQ_NOTSUPP; + + *complete = dfu_detach_complete; + return USBD_REQ_HANDLED; +} + +static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED) +{ + // We received a frame from the USB host + byte buf[8]; + uint len = usbd_ep_read_packet(dev, 0x01, buf, 8); + debug_printf("USB: Host sent %u bytes\n", len); + if (len >= 5) { + for (uint i=0; i<4; i++) { + disp[i] &= 0x01; + if (buf[i] < 16) + disp[i] |= disp_font[buf[i]]; + } + disp[1] &= 0xfe; + if (buf[4]) + disp[1] |= 0x01; + display_update(); + disp_alive = 10; + } +} + +static void ep82_send(u32 key_code) +{ + if (usb_tx_in_flight) { + debug_printf("USB: Send overrun!\n"); + return; } - usbd_ep_write_packet(usbd_dev, 0x81, buf, sizeof(buf)); + + debug_printf("USB: Sending key to host\n"); + put_u32_be(ep82_tx_buffer, key_code); + usbd_ep_write_packet(usbd_dev, 0x82, ep82_tx_buffer, 4); + usb_tx_in_flight = true; +} + +static void ep82_cb(usbd_device *dev UNUSED, uint8_t ep UNUSED) +{ + // We completed sending a frame to the USB host + usb_tx_in_flight = false; + debug_printf("USB: Key sending complete\n"); +} + +static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) +{ + usbd_register_control_callback( + dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + dfu_control_cb); + usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb); + usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_BULK, 4, ep82_cb); + usb_configured = true; +} + +static void reset_cb(void) +{ + debug_printf("USB: Reset\n"); + usb_configured = false; +} + +static volatile bool usb_event_pending; + +void usb_lp_can_rx0_isr(void) +{ + /* + * We handle USB in the main loop to avoid race conditions between + * USB interrupts and other code. However, we need an interrupt to + * up the main loop from sleep. + * + * We set up only the low-priority ISR, because high-priority ISR handles + * only double-buffered bulk transfers and isochronous transfers. + */ + nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ); + usb_event_pending = 1; } -static void set_config_cb(usbd_device *usbd_dev, uint16_t wValue UNUSED) +static void usb_init(void) { - usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb); - ep81_cb(usbd_dev, 0); + // 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(100); + + usbd_dev = usbd_init( + &st_usbfs_v1_usb_driver, + &device, + &config, + usb_strings, + ARRAY_SIZE(usb_strings), + 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); + usb_event_pending = 1; } +/*** Main ***/ + int main(void) { clock_init(); gpio_init(); - tick_init(); usart_init(); - // 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); + tick_init(); + desig_get_unique_id_as_dfu(usb_serial_number); - usbd_device *usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config_cb); - u32 last_ds_step = 0; + debug_printf("Hello, world!\n"); + + usb_init(); + display_init(); + ir_init(); + + u32 last_blink = 0; for (;;) { - if (ms_ticks - last_ds_step >= 100) { + if (ms_ticks - last_blink >= 500) { debug_led_toggle(); - ds_step(); - last_ds_step = ms_ticks; + last_blink = ms_ticks; + if (disp_alive) { + if (!--disp_alive) { + disp[0] = (disp[0] & 0x01) | 0x10; + disp[1] = (disp[1] & 0x01) | 0x10; + disp[2] = (disp[2] & 0x01) | 0x10; + disp[3] = (disp[3] & 0x01) | 0x10; + } + } + display_update(); + } + + if ((disp[3] & 0x01) && ms_ticks - ir_blink_start >= 100) { + disp[3] &= 0xfe; + display_update(); + } + + ir_decode(); + + if (usb_event_pending) { + usbd_poll(usbd_dev); + usb_event_pending = 0; + nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ); + nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); } - // XXX: libopencm3 usbd does not use interrupts at the moment, need to poll... - // wait_for_interrupt(); - usbd_poll(usbd_dev); + wait_for_interrupt(); } return 0; -- 2.39.2