Advertisement
Guest User

Adalight for Windows Boblight

a guest
Nov 10th, 2011
1,141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.99 KB | None | 0 0
  1. // Arduino "bridge" code between host computer and WS2801-based digital
  2. // RGB LED pixels (e.g. Adafruit product ID #322).  Intended for use
  3. // with USB-native boards such as Teensy or Adafruit 32u4 Breakout;
  4. // works on normal serial Arduinos, but throughput is severely limited.
  5. // LED data is streamed, not buffered, making this suitable for larger
  6. // installations (e.g. video wall, etc.) than could otherwise be held
  7. // in the Arduino's limited RAM.
  8.  
  9. // Some effort is put into avoiding buffer underruns (where the output
  10. // side becomes starved of data).  The WS2801 latch protocol, being
  11. // delay-based, could be inadvertently triggered if the USB bus or CPU
  12. // is swamped with other tasks.  This code buffers incoming serial data
  13. // and introduces intentional pauses if there's a threat of the buffer
  14. // draining prematurely.  The cost of this complexity is somewhat
  15. // reduced throughput, the gain is that most visual glitches are
  16. // avoided (though ultimately a function of the load on the USB bus and
  17. // host CPU, and out of our control).
  18.  
  19. // LED data and clock lines are connected to the Arduino's SPI output.
  20. // On traditional Arduino boards, SPI data out is digital pin 11 and
  21. // clock is digital pin 13.  On both Teensy and the 32u4 Breakout,
  22. // data out is pin B2, clock is B1.  LEDs should be externally
  23. // powered -- trying to run any more than just a few off the Arduino's
  24. // 5V line is generally a Bad Idea.  LED ground should also be
  25. // connected to Arduino ground.
  26.  
  27. #include <SPI.h>
  28.  
  29. // LED pin for Adafruit 32u4 Breakout Board:
  30. //#define LED_DDR  DDRE
  31. //#define LED_PORT PORTE
  32. //#define LED_PIN  _BV(PORTE6)
  33. // LED pin for Teensy:
  34. //#define LED_DDR  DDRD
  35. //#define LED_PORT PORTD
  36. //#define LED_PIN  _BV(PORTD6)
  37. // LED pin for Arduino:
  38. #define LED_DDR  DDRB
  39. #define LED_PORT PORTB
  40. #define LED_PIN  _BV(PORTB5)
  41.  
  42. // A 'magic word' (along with LED count & checksum) precedes each block
  43. // of LED data; this assists the microcontroller in syncing up with the
  44. // host-side software and properly issuing the latch (host I/O is
  45. // likely buffered, making usleep() unreliable for latch).  You may see
  46. // an initial glitchy frame or two until the two come into alignment.
  47. // The magic word can be whatever sequence you like, but each character
  48. // should be unique, and frequent pixel values like 0 and 255 are
  49. // avoided -- fewer false positives.  The host software will need to
  50. // generate a compatible header: immediately following the magic word
  51. // are three bytes: a 16-bit count of the number of LEDs (high byte
  52. // first) followed by a simple checksum value (high byte XOR low byte
  53. // XOR 0x55).  LED data follows, 3 bytes per LED, in order R, G, B,
  54. // where 0 = off and 255 = max brightness.
  55.  
  56. static const uint8_t magic[] = {0xff,0x00,0x00};
  57. #define MAGICSIZE  sizeof(magic)
  58. #define HEADERSIZE (MAGICSIZE + 1)
  59.  
  60. #define MODE_HEADER 0
  61. #define MODE_HOLD   1
  62. #define MODE_DATA   2
  63.  
  64. void setup()
  65. {
  66.   // Dirty trick: the circular buffer for serial data is 256 bytes,
  67.   // and the "in" and "out" indices are unsigned 8-bit types -- this
  68.   // much simplifies the cases where in/out need to "wrap around" the
  69.   // beginning/end of the buffer.  Otherwise there'd be a ton of bit-
  70.   // masking and/or conditional code every time one of these indices
  71.   // needs to change, slowing things down tremendously.
  72.   uint8_t
  73.     buffer[256],
  74.     indexIn       = 0,
  75.     indexOut      = 0,
  76.     mode          = MODE_HEADER,
  77.     hi, lo, chk, i, spiFlag;
  78.   int16_t
  79.     bytesBuffered = 0,
  80.     hold          = 0,
  81.     c;
  82.   int32_t
  83.     bytesRemaining;
  84.   unsigned long
  85.     startTime     = micros();
  86.  
  87.   LED_DDR  |=  LED_PIN; // Enable output for LED
  88.   LED_PORT &= ~LED_PIN; // LED off
  89.  
  90.   Serial.begin(115200); // Teensy/32u4 disregards baud rate; is OK!
  91.  
  92.   SPI.begin();
  93.   SPI.setBitOrder(MSBFIRST);
  94.   SPI.setDataMode(SPI_MODE0);
  95.   SPI.setClockDivider(SPI_CLOCK_DIV8);  // 2 MHz
  96.   // WS2801 datasheet recommends max SPI clock of 2 MHz, and 50 Ohm
  97.   // resistors on SPI lines for impedance matching.  In practice and
  98.   // at short distances, 2 MHz seemed to work reliably enough without
  99.   // resistors, and 4 MHz was possible with a 220 Ohm resistor on the
  100.   // SPI clock line only.  Your mileage may vary.  Experiment!
  101.   // SPI.setClockDivider(SPI_CLOCK_DIV4);  // 4 MHz
  102.  
  103.   // Issue test pattern to LEDs on startup.  This helps verify that
  104.   // wiring between the Arduino and LEDs is correct.  Not knowing the
  105.   // actual number of LEDs connected, this sets all of them (well, up
  106.   // to the first 25,000, so as not to be TOO time consuming) to red,
  107.   // green, blue, then off.  Once you're confident everything is working
  108.   // end-to-end, it's OK to comment this out and reprogram the Arduino.
  109.   uint8_t testcolor[] = { 0, 0, 0, 255, 0, 0 };
  110.   for(char n=3; n>=0; n--) {
  111.     for(c=0; c<25000; c++) {
  112.       for(i=0; i<3; i++) {
  113.         for(SPDR = testcolor[n + i]; !(SPSR & _BV(SPIF)); );
  114.       }
  115.     }
  116.     delay(1); // One millisecond pause = latch
  117.   }
  118.  
  119.   // loop() is avoided as even that small bit of function overhead
  120.   // has a measurable impact on this code's overall throughput.
  121.  
  122.   for(;;) {
  123.  
  124.     // Implementation is a simple finite-state machine.
  125.     // Regardless of mode, check for serial input each time:
  126.     if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) {
  127.       buffer[indexIn++] = c;
  128.       bytesBuffered++;
  129.     }
  130.  
  131.     switch(mode) {
  132.  
  133.      case MODE_HEADER:
  134.  
  135.       // In header-seeking mode.  Is there enough data to check?
  136.       if(bytesBuffered >= HEADERSIZE) {
  137.         // Indeed.  Check for a 'magic word' match.
  138.         for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
  139.         if(i == MAGICSIZE) {
  140.           // Magic word matches.  Now how about the checksum?
  141.           //hi  = buffer[indexOut++];
  142.           //lo  = buffer[indexOut++];
  143.           //chk = buffer[indexOut++];
  144.           //if(chk == (hi ^ lo ^ 0x55)) {
  145.             // Checksum looks valid.  Get 16-bit LED count, add 1
  146.             // (# LEDs is always > 0) and multiply by 3 for R,G,B.
  147.             bytesRemaining = buffer[indexOut++];//3L * (256L * (long)hi + (long)lo + 1L);
  148.             bytesBuffered -= 1;
  149.             spiFlag        = 0;         // No data out yet
  150.             mode           = MODE_HOLD; // Proceed to latch wait mode
  151.           //} else {
  152.             // Checksum didn't match; search resumes after magic word.
  153.           //  indexOut  -= 1; // Rewind
  154.           //}
  155.         } // else no header match.  Resume at first mismatched byte.
  156.         bytesBuffered -= i;
  157.       }
  158.       break;
  159.  
  160.      case MODE_HOLD:
  161.  
  162.       // Ostensibly "waiting for the latch from the prior frame
  163.       // to complete" mode, but may also revert to this mode when
  164.       // underrun prevention necessitates a delay.
  165.  
  166.       if((micros() - startTime) < hold) break; // Still holding; keep buffering
  167.  
  168.       // Latch/delay complete.  Advance to data-issuing mode...
  169.       LED_PORT &= ~LED_PIN;  // LED off
  170.       mode      = MODE_DATA; // ...and fall through (no break):
  171.  
  172.      case MODE_DATA:
  173.  
  174.       while(spiFlag && !(SPSR & _BV(SPIF))); // Wait for prior byte
  175.       if(bytesRemaining > 0) {
  176.         if(bytesBuffered > 0) {
  177.           SPDR = buffer[indexOut++];   // Issue next byte
  178.           bytesBuffered--;
  179.           bytesRemaining--;
  180.           spiFlag = 1;
  181.         }
  182.         // If serial buffer is threatening to underrun, start
  183.         // introducing progressively longer pauses to allow more
  184.         // data to arrive (up to a point).
  185.         if((bytesBuffered < 32) && (bytesRemaining > bytesBuffered)) {
  186.           startTime = micros();
  187.           hold      = 100 + (32 - bytesBuffered) * 10;
  188.           mode      = MODE_HOLD;
  189.     }
  190.       } else {
  191.         // End of data -- issue latch:
  192.         startTime  = micros();
  193.         hold       = 1000;        // Latch duration = 1000 uS
  194.         LED_PORT  |= LED_PIN;     // LED on
  195.         mode       = MODE_HEADER; // Begin next header search
  196.       }
  197.     } // end switch
  198.   } // end for(;;)
  199. }
  200.  
  201. void loop()
  202. {
  203.   // Not used.  See note in setup() function.
  204. }
  205.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement