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);
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);
// 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)
/*** 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 ***/
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)
dmx_init();
u32 last_blink = 0;
+ u32 last_send = 0;
for (;;) {
if (ms_ticks - last_blink >= 100) {
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();
}