src/dmx_frame.c
changeset 62 2d68a76322cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmx_frame.c	Sun Apr 06 18:25:55 2014 +0300
@@ -0,0 +1,49 @@
+/*
+ * Per-frame timing-critical bit-banging.
+ *
+ * Shamelessly stolen from
+ *  http://code.google.com/p/tinkerit/source/browse/trunk/DmxSimple/DmxSimple.cpp
+ *
+ *  Copyright (c) 2008-2009 Peter Knight, Tinker.it!
+ *
+ * Consumes approx. 11 * 64 ~= 705 clock cycles
+ * Leaves the line idle (high) on return.
+ */
+void dmx_frame (volatile byte value)
+{
+  uint8_t bitCount, delCount;
+  __asm__ volatile (
+    "cli\n"
+    "ld __tmp_reg__,%a[dmxPort]\n"
+    "and __tmp_reg__,%[outMask]\n"
+    "st %a[dmxPort],__tmp_reg__\n"
+    "ldi %[bitCount],11\n" // 11 bit intervals per transmitted byte
+    "rjmp bitLoop%=\n"     // Delay 2 clock cycles.
+  "bitLoop%=:\n"\
+    "ldi %[delCount],%[delCountVal]\n"
+  "delLoop%=:\n"
+    "nop\n"
+    "dec %[delCount]\n"
+    "brne delLoop%=\n"
+    "ld __tmp_reg__,%a[dmxPort]\n"
+    "and __tmp_reg__,%[outMask]\n"
+    "sec\n"
+    "ror %[value]\n"
+    "brcc sendzero%=\n"
+    "or __tmp_reg__,%[outBit]\n"
+  "sendzero%=:\n"
+    "st %a[dmxPort],__tmp_reg__\n"
+    "dec %[bitCount]\n"
+    "brne bitLoop%=\n"
+    "sei\n"
+    :
+      [bitCount] "=&d" (bitCount),
+      [delCount] "=&d" (delCount)
+    :
+      [dmxPort] "e" (&DMX_PORT),
+      [outMask] "r" (~(1 << DMX_DATA)),
+      [outBit] "r" ((1 << DMX_DATA)),
+      [delCountVal] "M" (F_CPU/1000000-3),
+      [value] "r" (value)
+  );
+}