PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
8.0KB

  1. /**
  2. * DmxSimple - A simple interface to DMX.
  3. *
  4. * Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved.
  5. */
  6. // modified to support all Teensy boards
  7. #include <avr/io.h>
  8. #include <avr/interrupt.h>
  9. #include <util/delay.h>
  10. #include "pins_arduino.h"
  11. #include "Arduino.h"
  12. #include "DmxSimple.h"
  13. /** dmxBuffer contains a software copy of all the DMX channels.
  14. */
  15. volatile uint8_t dmxBuffer[DMX_SIZE];
  16. static uint16_t dmxMax = 16; /* Default to sending the first 16 channels */
  17. static uint8_t dmxStarted = 0;
  18. static uint16_t dmxState = 0;
  19. #if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41)
  20. // Teensy 4.X has 32-bit ports
  21. static volatile uint32_t *dmxPort;
  22. #else
  23. static volatile uint8_t *dmxPort;
  24. #endif
  25. static uint8_t dmxBit = 0;
  26. static uint8_t dmxPin = 3; // Defaults to output on pin 3 to support Tinker.it! DMX shield
  27. void dmxBegin();
  28. void dmxEnd();
  29. void dmxSendByte(volatile uint8_t);
  30. void dmxWrite(int,uint8_t);
  31. void dmxMaxChannel(int);
  32. /* TIMER2 has a different register mapping on the ATmega8.
  33. * The modern chips (168, 328P, 1280) use identical mappings.
  34. */
  35. #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  36. #define TIMER2_INTERRUPT_ENABLE() TIMSK2 |= _BV(TOIE2)
  37. #define TIMER2_INTERRUPT_DISABLE() TIMSK2 &= ~_BV(TOIE2)
  38. #define ISR_NAME TIMER2_OVF_vect
  39. #define BITS_PER_TIMER_TICK (F_CPU / 31372)
  40. // older ATMEGA8 has slighly different timer2
  41. #elif defined(__AVR_ATmega8__)
  42. #define TIMER2_INTERRUPT_ENABLE() TIMSK |= _BV(TOIE2)
  43. #define TIMER2_INTERRUPT_DISABLE() TIMSK &= ~_BV(TOIE2)
  44. #define ISR_NAME TIMER2_OVF_vect
  45. #define BITS_PER_TIMER_TICK (F_CPU / 31372)
  46. // ATMEGA32U4 on Teensy and Leonardo has no timer2, but has timer4
  47. #elif defined (__AVR_ATmega32U4__)
  48. #define TIMER2_INTERRUPT_ENABLE() TIMSK4 |= _BV(TOIE4)
  49. #define TIMER2_INTERRUPT_DISABLE() TIMSK4 &= ~_BV(TOIE4)
  50. #define ISR_NAME TIMER4_OVF_vect
  51. #define BITS_PER_TIMER_TICK (F_CPU / 31372)
  52. // Teensy 3.0 has IntervalTimer, unrelated to any PWM signals
  53. #elif defined(CORE_TEENSY) && defined(__arm__)
  54. #define TIMER2_INTERRUPT_ENABLE()
  55. #define TIMER2_INTERRUPT_DISABLE()
  56. #define ISR_NAME DMXinterrupt
  57. #define ISR(function, option) void function(void)
  58. #define BITS_PER_TIMER_TICK 500
  59. void DMXinterrupt(void);
  60. IntervalTimer DMXtimer;
  61. #else
  62. #define TIMER2_INTERRUPT_ENABLE()
  63. #define TIMER2_INTERRUPT_DISABLE()
  64. #define ISR_NAME TIMER2_OVF_vect
  65. /* Produce an error (warnings to not print on Arduino's default settings)
  66. */
  67. #error "DmxSimple does not support this CPU"
  68. #endif
  69. /** Initialise the DMX engine
  70. */
  71. void dmxBegin()
  72. {
  73. dmxStarted = 1;
  74. // Set up port pointers for interrupt routine
  75. dmxPort = portOutputRegister(digitalPinToPort(dmxPin));
  76. dmxBit = digitalPinToBitMask(dmxPin);
  77. // Set DMX pin to output
  78. pinMode(dmxPin,OUTPUT);
  79. // Initialise DMX frame interrupt
  80. //
  81. // Presume Arduino has already set Timer2 to 64 prescaler,
  82. // Phase correct PWM mode
  83. // So the overflow triggers every 64*510 clock cycles
  84. // Which is 510 DMX bit periods at 16MHz,
  85. // 255 DMX bit periods at 8MHz,
  86. // 637 DMX bit periods at 20MHz
  87. #if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  88. TCCR2A = (1<<WGM20);
  89. TCCR2B = (1<<CS22); // 64 prescaler
  90. #elif defined (__AVR_ATmega32U4__)
  91. TCCR4B = (1<<CS42)|(1<<CS41)|(1<<CS40);
  92. #elif defined(CORE_TEENSY) && defined(__arm__)
  93. DMXtimer.begin(DMXinterrupt, 2000);
  94. #endif
  95. TIMER2_INTERRUPT_ENABLE();
  96. }
  97. /** Stop the DMX engine
  98. * Turns off the DMX interrupt routine
  99. */
  100. void dmxEnd()
  101. {
  102. TIMER2_INTERRUPT_DISABLE();
  103. #if defined(CORE_TEENSY) && defined(__arm__)
  104. DMXtimer.end();
  105. #endif
  106. dmxStarted = 0;
  107. dmxMax = 0;
  108. }
  109. /** Transmit a complete DMX byte
  110. * We have no serial port for DMX, so everything is timed using an exact
  111. * number of instruction cycles.
  112. *
  113. * Really suggest you don't touch this function.
  114. */
  115. #if defined(__AVR__)
  116. void dmxSendByte(volatile uint8_t value)
  117. {
  118. uint8_t bitCount, delCount;
  119. __asm__ volatile (
  120. "cli\n"
  121. "ld __tmp_reg__,%a[dmxPort]\n"
  122. "and __tmp_reg__,%[outMask]\n"
  123. "st %a[dmxPort],__tmp_reg__\n"
  124. "ldi %[bitCount],11\n" // 11 bit intervals per transmitted byte
  125. "rjmp bitLoop%=\n" // Delay 2 clock cycles.
  126. "bitLoop%=:\n"\
  127. "ldi %[delCount],%[delCountVal]\n"
  128. "delLoop%=:\n"
  129. "nop\n"
  130. "dec %[delCount]\n"
  131. "brne delLoop%=\n"
  132. "ld __tmp_reg__,%a[dmxPort]\n"
  133. "and __tmp_reg__,%[outMask]\n"
  134. "sec\n"
  135. "ror %[value]\n"
  136. "brcc sendzero%=\n"
  137. "or __tmp_reg__,%[outBit]\n"
  138. "sendzero%=:\n"
  139. "st %a[dmxPort],__tmp_reg__\n"
  140. "dec %[bitCount]\n"
  141. "brne bitLoop%=\n"
  142. "sei\n"
  143. :
  144. [bitCount] "=&d" (bitCount),
  145. [delCount] "=&d" (delCount)
  146. :
  147. [dmxPort] "e" (dmxPort),
  148. [outMask] "r" (~dmxBit),
  149. [outBit] "r" (dmxBit),
  150. [delCountVal] "M" (F_CPU/1000000-3),
  151. [value] "r" (value)
  152. );
  153. }
  154. #elif defined(__arm__)
  155. void dmxSendByte(uint8_t value)
  156. {
  157. uint32_t begin, target;
  158. uint8_t mask;
  159. noInterrupts();
  160. ARM_DEMCR |= ARM_DEMCR_TRCENA;
  161. ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  162. begin = ARM_DWT_CYCCNT;
  163. *dmxPort = 0;
  164. target = F_CPU / 250000;
  165. while (ARM_DWT_CYCCNT - begin < target) ; // wait, start bit
  166. for (mask=1; mask; mask <<= 1) {
  167. *dmxPort = (value & mask) ? 1 : 0;
  168. target += (F_CPU / 250000);
  169. while (ARM_DWT_CYCCNT - begin < target) ; // wait, data bits
  170. }
  171. *dmxPort = 1;
  172. target += (F_CPU / 125000);
  173. while (ARM_DWT_CYCCNT - begin < target) ; // wait, 2 stops bits
  174. interrupts();
  175. }
  176. #endif
  177. /** DmxSimple interrupt routine
  178. * Transmit a chunk of DMX signal every timer overflow event.
  179. *
  180. * The full DMX transmission takes too long, but some aspects of DMX timing
  181. * are flexible. This routine chunks the DMX signal, only sending as much as
  182. * it's time budget will allow.
  183. *
  184. * This interrupt routine runs with interrupts enabled most of the time.
  185. * With extremely heavy interrupt loads, it could conceivably interrupt its
  186. * own routine, so the TIMER2 interrupt is disabled for the duration of
  187. * the service routine.
  188. */
  189. ISR(ISR_NAME,ISR_NOBLOCK) {
  190. // Prevent this interrupt running recursively
  191. TIMER2_INTERRUPT_DISABLE();
  192. uint16_t bitsLeft = BITS_PER_TIMER_TICK; // DMX Bit periods per timer tick
  193. bitsLeft >>=2; // 25% CPU usage
  194. while (1) {
  195. if (dmxState == 0) {
  196. // Next thing to send is reset pulse and start code
  197. // which takes 35 bit periods
  198. uint8_t i;
  199. if (bitsLeft < 35) break;
  200. bitsLeft-=35;
  201. *dmxPort &= ~dmxBit;
  202. for (i=0; i<11; i++) delayMicroseconds(8);
  203. *dmxPort |= dmxBit;
  204. delayMicroseconds(12);
  205. dmxSendByte(0);
  206. } else {
  207. // Now send a channel which takes 11 bit periods
  208. if (bitsLeft < 11) break;
  209. bitsLeft-=11;
  210. dmxSendByte(dmxBuffer[dmxState-1]);
  211. }
  212. // Successfully completed that stage - move state machine forward
  213. dmxState++;
  214. if (dmxState > dmxMax) {
  215. dmxState = 0; // Send next frame
  216. break;
  217. }
  218. }
  219. // Enable interrupts for the next transmission chunk
  220. TIMER2_INTERRUPT_ENABLE();
  221. }
  222. void dmxWrite(int channel, uint8_t value) {
  223. if (!dmxStarted) dmxBegin();
  224. if ((channel > 0) && (channel <= DMX_SIZE)) {
  225. if (value<0) value=0;
  226. if (value>255) value=255;
  227. dmxMax = max((unsigned)channel, dmxMax);
  228. dmxBuffer[channel-1] = value;
  229. }
  230. }
  231. void dmxMaxChannel(int channel) {
  232. if (channel <=0) {
  233. // End DMX transmission
  234. dmxEnd();
  235. dmxMax = 0;
  236. } else {
  237. dmxMax = min(channel, DMX_SIZE);
  238. if (!dmxStarted) dmxBegin();
  239. }
  240. }
  241. /* C++ wrapper */
  242. /** Set output pin
  243. * @param pin Output digital pin to use
  244. */
  245. void DmxSimpleClass::usePin(uint8_t pin) {
  246. bool restartRequired = dmxStarted;
  247. if (restartRequired) dmxEnd();
  248. dmxPin = pin;
  249. if (restartRequired) dmxBegin();
  250. }
  251. /** Set DMX maximum channel
  252. * @param channel The highest DMX channel to use
  253. */
  254. void DmxSimpleClass::maxChannel(int channel) {
  255. dmxMaxChannel(channel);
  256. }
  257. /** Write to a DMX channel
  258. * @param address DMX address in the range 1 - 512
  259. */
  260. void DmxSimpleClass::write(int address, uint8_t value)
  261. {
  262. dmxWrite(address, value);
  263. }
  264. DmxSimpleClass DmxSimple;