X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=dmx%2Ffirmware%2Fmain.c;h=47ff5d35e3cb7d34fa70e8c46552f2692626f997;hb=HEAD;hp=c8d35b5cac287732074231c9171170ad6b6d9d3b;hpb=fc7da8e5a98bac56af0b95d197d87b7e571111fc;p=home-hw.git diff --git a/dmx/firmware/main.c b/dmx/firmware/main.c index c8d35b5..47ff5d3 100644 --- a/dmx/firmware/main.c +++ b/dmx/firmware/main.c @@ -30,6 +30,7 @@ static void clock_init(void) rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_TIM3); rcc_periph_clock_enable(RCC_USART1); rcc_periph_clock_enable(RCC_USART3); rcc_periph_clock_enable(RCC_USB); @@ -37,6 +38,7 @@ static void clock_init(void) rcc_periph_reset_pulse(RST_GPIOA); rcc_periph_reset_pulse(RST_GPIOB); rcc_periph_reset_pulse(RST_GPIOC); + rcc_periph_reset_pulse(RST_TIM3); rcc_periph_reset_pulse(RST_USART1); rcc_periph_reset_pulse(RST_USART3); rcc_periph_reset_pulse(RST_USB); @@ -55,8 +57,12 @@ static void gpio_init(void) // PB10 = TXD3 for DMX // PB11 = RXD3 for DMX - gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10); + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO10); gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11); + + // PB1 = TX enable for DMX (always on) + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO1); + gpio_set(GPIOB, GPIO1); } static void usart_init(void) @@ -96,36 +102,141 @@ static void delay_ms(uint ms) /*** DMX ***/ +#define DMX_MAX_PACKET_SIZE 64 + +static volatile byte dmx_state; +static byte dmx_packet[DMX_MAX_PACKET_SIZE]; +static byte dmx_pos, dmx_len; + +static byte dmx_next_packet[DMX_MAX_PACKET_SIZE]; +static byte dmx_next_len; + +#undef DEBUG_DMX +#ifdef DEBUG_DMX +#define DMX_DEBUG(ch) debug_putc(ch) +#else +#define DMX_DEBUG(ch) do { } while (0) +#endif + +enum dmx_state { + DMX_STATE_IDLE = 0, + DMX_STATE_BREAK, + DMX_STATE_MARK, + DMX_STATE_DATA, + DMX_STATE_LAST_BYTE, + DMX_STATE_GAP, +}; + static void dmx_init(void) { usart_set_baudrate(USART3, 250000); usart_set_databits(USART3, 8); - usart_set_stopbits(USART3, USART_STOPBITS_1); + usart_set_stopbits(USART3, USART_STOPBITS_2); usart_set_mode(USART3, USART_MODE_TX); usart_set_parity(USART3, USART_PARITY_NONE); usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE); + nvic_enable_irq(NVIC_USART3_IRQ); usart_enable(USART3); + + timer_set_prescaler(TIM3, CPU_CLOCK_MHZ - 1); // 1 MHz + timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_update_on_overflow(TIM3); + timer_disable_preload(TIM3); + timer_one_shot_mode(TIM3); + timer_enable_irq(TIM3, TIM_DIER_UIE); + nvic_enable_irq(NVIC_TIM3_IRQ); + + // Until we get data from USB, send "turn everything off" packets + memset(dmx_next_packet, 0, DMX_MAX_PACKET_SIZE); + dmx_next_len = DMX_MAX_PACKET_SIZE; +} + +void tim3_isr(void) +{ + if (TIM_SR(TIM3) & TIM_SR_UIF) { + TIM_SR(TIM3) &= ~TIM_SR_UIF; + switch (dmx_state) { + case DMX_STATE_BREAK: + // Send mark for 50 μs + DMX_DEBUG('m'); + dmx_state = DMX_STATE_MARK; + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10); + timer_set_period(TIM3, 199); + timer_generate_event(TIM3, TIM_EGR_UG); + timer_enable_counter(TIM3); + break; + case DMX_STATE_MARK: + // Start sending data bytes + DMX_DEBUG('d'); + dmx_state = DMX_STATE_DATA; + usart_enable_tx_interrupt(USART3); + break; + case DMX_STATE_GAP: + DMX_DEBUG('>'); + dmx_state = DMX_STATE_IDLE; + break; + } + } +} + +void usart3_isr(void) +{ + u32 status = USART_SR(USART3); + + if (dmx_state == DMX_STATE_DATA) { + if (status & USART_SR_TXE) { + if (dmx_pos < dmx_len) { + DMX_DEBUG('.'); + usart_send(USART3, dmx_packet[dmx_pos++]); + } else { + // The transmitter is double-buffered, so at this moment, it is transmitting + // the last byte of the frame. Wait until transfer is completed. + DMX_DEBUG('l'); + usart_disable_tx_interrupt(USART3); + USART_CR1(USART3) |= USART_CR1_TCIE; + dmx_state = DMX_STATE_LAST_BYTE; + } + } + } else if (dmx_state == DMX_STATE_LAST_BYTE) { + // Transfer of the last byte is complete, but we have to wait + // before the start of the next packet: minimum time between two + // breaks must be at least 1204 μs. We already sent a 200μs break, + // 200μs mark, and dmx_len 44μs data slots. + USART_CR1(USART3) &= ~USART_CR1_TCIE; + uint sent = 200 + 200 + 44*dmx_len; + if (sent < 1300) { + DMX_DEBUG('g'); + dmx_state = DMX_STATE_GAP; + timer_set_period(TIM3, 1300 - sent - 1); + timer_generate_event(TIM3, TIM_EGR_UG); + timer_enable_counter(TIM3); + } else { + DMX_DEBUG('>'); + dmx_state = DMX_STATE_IDLE; + } + } } static void dmx_send(void) { - delay_ms(1); + if (dmx_state != DMX_STATE_IDLE) + return; - // Send break + if (!dmx_len) + return; + + dmx_pos = 0; + + // Send break for 200 μs + DMX_DEBUG('<'); + dmx_state = DMX_STATE_BREAK; gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO10); gpio_clear(GPIOB, GPIO10); - delay_ms(1); - - // Send space - gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO10); - delay_ms(1); - usart_send_blocking(USART3, 0x00); - usart_send_blocking(USART3, 0x00); - usart_send_blocking(USART3, 0xff); // warm - usart_send_blocking(USART3, 0x00); - usart_send_blocking(USART3, 0x00); // cold + timer_set_period(TIM3, 199); + timer_generate_event(TIM3, TIM_EGR_UG); + timer_enable_counter(TIM3); } /*** USB ***/ @@ -257,9 +368,9 @@ static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED, static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED) { // We received a frame from the USB host - byte buf[64]; - uint len = usbd_ep_read_packet(dev, 0x01, buf, sizeof(buf)); + uint len = usbd_ep_read_packet(dev, 0x01, dmx_next_packet, DMX_MAX_PACKET_SIZE); debug_printf("USB: Host sent %u bytes\n", len); + dmx_next_len = len; } static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) @@ -332,6 +443,7 @@ int main(void) dmx_init(); u32 last_blink = 0; + u32 last_send = 0; for (;;) { if (ms_ticks - last_blink >= 100) { @@ -347,6 +459,23 @@ int main(void) nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); } + if (dmx_state == DMX_STATE_IDLE) { + if (dmx_next_len) { + // We have a new packet to send + debug_printf("Sending new packet: %d bytes\n", dmx_next_len); + memcpy(dmx_packet, dmx_next_packet, dmx_next_len); + dmx_len = dmx_next_len; + dmx_next_len = 0; + dmx_send(); + last_send = ms_ticks; + } else if (ms_ticks - last_send >= 100) { + // Re-send every 100 ms + // debug_printf("Re-send: %d bytes\n", dmx_len); + dmx_send(); + last_send = ms_ticks; + } + } + wait_for_interrupt(); }