And finally... a working state machine!
authorMalte S. Stretz <mss@apache.org>
Wed, 11 Feb 2009 15:48:10 +0000 (15:48 +0000)
committerMalte S. Stretz <mss@apache.org>
Wed, 11 Feb 2009 15:48:10 +0000 (15:48 +0000)
src/dmx.c
src/dmx.h
src/main.c
src/mcu_config.h

index 7db8f05..a81b5ff 100644 (file)
--- a/src/dmx.c
+++ b/src/dmx.c
 #include "buffer.h"
 
 
-
-
-void set_timer(int8_t ms)
+void enable_timer(int8_t us)
 {
-  // Set counter to trigger correct overflow.
-  TCNT0 = 0xFF - 2 * ms;
+  // Prepare timer counter.
+  TCNT0 = 0xFF - 2 * us;
 
-  // Enable timer interrupt (p72)
-  bits_on(TIMSK, TOIE0);
+  // Enable timer, use a frequency prescaler of 8 (p72).
+  bits_mask_on(TCCR0, (1 << CS01));
 }
 
-void set_timer_off(void)
+void disable_timer(void)
 {
-  // Disable timer interrupt (p72).
-  bits_off(TIMSK, TOIE0);
+  // Disable timer (p72).
+  bits_mask_off(TCCR0, (1 << CS02) | (1 << CS01) | (1 << CS00));
 }
 
-void set_trigger_rising(void)
-{
-  // Trigger on rising edge.
-  bits_on(MCUCR, ISC00);
 
+void enable_trigger(void)
+{
   // Enable interrupt.
   bits_on(GICR, INT0);
 }
 
-void set_trigger_falling(void)
+void disable_trigger(void)
 {
-  // Trigger on falling edge.
-  bits_off(MCUCR, ISC00);
+  // Disable interrupt.
+  bits_off(GICR, INT0);
+}
 
-  // Enable interrupt.
-  bits_on(GICR, INT0);
+void enable_usart(void)
+{
+  // Enable RXD.
+  bits_on(UCSRB, RXEN);
 }
 
-void set_trigger_off(void)
+void disable_usart(void)
 {
-  // Disable interrupt.
-  bits_off(GICR, INT0);
+  // Disable RXD.
+  bits_off(UCSRB, RXEN);
 }
 
 ///////////////////////////////
 
 void dmx_init(void)
 {
-  // Use a frequency prescaler of 8 (p72).
-  bits_mask_on(TCCR0, 1 << CS01);
-
-  // Configure as input.
-  pin_in(PIN_DMX);
-
-  // Prepare INT0, set_trigger_* will toggle between edges.
-  set_trigger_off();
-  bits_on(MCUCR, ISC01);
+  // Configure both pins as input.
+  pin_in(PIN_DMX_INT);
+  pin_in(PIN_DMX_RXD);
+
+  // Initialize USART (p156) with
+  // 250kbaud    (UBRR = 3),
+  // 8 data bits (UCSZ = 011),
+  // 2 stop bits (USBS = 1),
+  // no parity   (UPM  = 00).
+  UBRRL = F_CPU / (16 * 250e3) - 1;
+  //UBRRL = 6;
+  UBRRH = (0 << URSEL) | 0;
+  UCSRC = (1 << URSEL)
+        | bits_value(UCSZ1) | bits_value(UCSZ0)
+        | bits_value(USBS);
+  // Enable USART RXD interrupt (and clear UCSZ2 and *XEN).
+  UCSRB = bits_value(RXCIE);
+  //UCSRA = bits_value(U2X);
+  bits_on(UCSRB, TXEN);
+
+  // Enable timer interrupt (p72).
+  bits_on(TIMSK, TOIE0);
 
-  // Enable interrupt after a short while.
-  set_timer(10);
+  // Trigger INT0 on any edge (ISC0 = 01, p67).
+  bits_on(MCUCR, ISC00);
+  enable_trigger();
 }
 
-///////////////////////////////
-
-enum state_enum {
+enum {
   STATE_IDLE,
-  STATE_WAIT,
-  STATE_MARK,
   STATE_SYNC,
-  STATE_READ,
+  STATE_WAIT,
+  STATE_RECV,
   STATE_STOR
-};
+} g_state;
+int16_t g_index;
 
-uint8_t  g_package_buffer;
-uint8_t  g_package_mask;
-int16_t  g_package_index;
-enum state_enum g_state = STATE_IDLE;
 
 void dmx_int_timer0_ovf(void)
 {
   // Disable this interrupt.
-  set_timer_off();
+  disable_timer();
 
-  switch (g_state)
-  {
-    case STATE_IDLE: {
-      // The line must be High when idle.
-      if (pin_is_set(PIN_DMX)) {
-        // Wait for start of Reset.
-        set_trigger_falling();
-      }
-      else {
-        // Wait for High.
-        set_timer(10);
-      }
+  switch (g_state) {
+    case STATE_SYNC: {
+      // Line was low for 88 us, all is fine.
+      //mcu_debug_off();
+      g_state = STATE_WAIT;
       break;
     }
-    
-    case STATE_WAIT: {
-      // Reset was held for 88 us, wait for end of Mark now.
-      mcu_debug();
-      set_trigger_falling();
-      g_package_index = -1;
-      g_state = STATE_MARK;
+    case STATE_RECV:
+    case STATE_STOR: {
+      // We got a timeout, back to Idle.
+      disable_usart();
+      enable_trigger();
+      g_state = STATE_IDLE;
       break;
     }
-
-    case STATE_SYNC: {
-      // Now read the data, LSB first.
-      set_timer(4);
-      g_package_mask = bits_uint8(0, 0, 0, 0, 0, 0, 0, 1);
-      g_state = STATE_READ;
+    default: {
       break;
     }
+  }
+  
+}
 
-    case STATE_READ: {
-      // Prepare next timer.
-      set_timer(4);
-
-      // Read bit.
-      if (pin_is_set(PIN_DMX)) {
-        bits_mask_on( g_package_buffer, g_package_mask);
-      } else {
-        bits_mask_off(g_package_buffer, g_package_mask);
-      }
-
-      // Prepare next bit.
-      g_package_mask <<= 1;
-      if (g_package_mask == 0) {
-        // Got a full package, store it.
-        set_timer(1);
-        g_state = STATE_STOR;
+void dmx_int_ext(void)
+{
+  switch (g_state) {
+    case STATE_IDLE: {
+      // Only trigger on fallen edge.
+      if (!pin_is_set(PIN_DMX_RXD)) {
+        // Wait for 88 us.
+        enable_timer(88);
+        mcu_debug_off();
+        //mcu_debug_on();
+        g_state = STATE_SYNC;
       }
       break;
     }
-
-    case STATE_STOR: {
-      // Store byte, but skip start byte.
-      if (g_package_index != -1) {
-        //gg_buffer_gs[g_package_index] = g_package_buffer;
-      }
-      // Next byte.
-      g_package_index++;
-
-      // Wait for next package or next frame.
-      if (g_package_index != 512) {
-        set_trigger_falling();
-        g_state = STATE_MARK;
-      }
-      else {
-        set_timer(20);
-        g_state = STATE_IDLE;
-      }
+    case STATE_SYNC: {
+      // Got a stray edge while Reset, back to Idle.
+      disable_timer();
+      //mcu_debug_off();
+      g_state = STATE_IDLE;
+      break;
+    }
+    case STATE_WAIT: {
+      // This edge is the Mark, start the USART and disable
+      // this interrupt.
+      disable_trigger();
+      enable_usart();
+            mcu_debug_on();      mcu_debug_off();
+      g_state = STATE_RECV;
       break;
     }
-
     default: {
       break;
     }
   }
 }
 
-
-void dmx_int_ext(void)
+void dmx_int_usart_rxc(void)
 {
-  // Disable this interrupt.
-  set_trigger_off();
+  // Read USART data (p146).
+  uint8_t rxd;
+  uint8_t err;
+  // Read Frame Error flag.
+  err = UCSRA & bits_value(FE);
+  // Read data byte (and clear RXC flag).
+  rxd = UDR;
+        
+  if (err) {
+  mcu_debug_on();      mcu_debug_off();
+    goto last;
+  }
 
-  switch (g_state)
-  {
-    case STATE_IDLE: {
-      // Wait for end of Reset.
-      set_timer(88);
-      set_trigger_rising();
-      g_state = STATE_WAIT;
+  switch (g_state) {
+    case STATE_RECV: {
+      // Check for valid start byte.
+      //if (rxd & (1 << 0)) { mcu_debug_on(); } else { mcu_debug_off(); }
+      /*if (rxd != 0x00) {
+        goto last;
+      }*/
+      
+      // Switch to data storage.
+      g_index = 0;
+      g_state = STATE_STOR;
       break;
     }
-
-    case STATE_WAIT: {
-      // We got a stray edge before Reset timeout, back to IDLE.
-      set_timer(1);
-      g_state = STATE_IDLE;
-      break;
-    }
-
-    case STATE_MARK: {
-      // We got our start bit, sync to middle.
-      mcu_debug();
-      set_timer(2);
-      g_state = STATE_SYNC;
+    case STATE_STOR: {
+      // Write byte to buffer.
+      gg_buffer_gs[g_index] = rxd;
+      // Next index.
+      g_index++;
+      if (g_index == 512) {
+        goto last;
+      }
       break;
     }
-
     default: {
       break;
     }
   }
-}
 
+  return;
+last:
+  // Either an invalid or the last frame appeared, stop DMX.
+  disable_usart();
+  enable_trigger();
+  g_state = STATE_IDLE;
+  return;
+}
index b5f7fb9..be45782 100644 (file)
--- a/src/dmx.h
+++ b/src/dmx.h
@@ -4,3 +4,4 @@ void dmx_init(void);
 
 void dmx_int_ext(void);
 void dmx_int_timer0_ovf(void);
+void dmx_int_usart_rxc(void);
index 84d2007..4ab476f 100644 (file)
 
 // INT0:  External int, DMX sync
 mcu_isr(INT0);
-
 // TIMER0:  8-Bit: 4 us for DMX, timeouts
 mcu_isr(TIMER0_OVF);
+// USART:  RXD
+mcu_isr(USART_RXC);
 
 // TIMER1: 16-Bit: GSCLK
 mcu_isr(TIMER1_COMPA);
index eb4db61..91264df 100644 (file)
@@ -7,12 +7,14 @@
 #define PIN_TLC_BLNK  PIN_25
 #define PIN_TLC_VPRG  PIN_24
 
-#define PIN_DMX   PIN_INT0
+#define PIN_DMX_INT   PIN_INT0
+#define PIN_DMX_RXD   PIN_RXD
 
 #define INT_TIMER1_COMPA tlc_int_timer1_ocma
 #define INT_TIMER2_COMP  tlc_int_timer2_ocm
 
 #define INT_TIMER0_OVF   dmx_int_timer0_ovf
 #define INT_INT0         dmx_int_ext
+#define INT_USART_RXC    dmx_int_usart_rxc
 
 #define PIN_DEBUG     PIN_14