Skip to content

Instantly share code, notes, and snippets.

@tvdzwan
Last active January 5, 2020 20:10
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tvdzwan/9008833 to your computer and use it in GitHub Desktop.
Save tvdzwan/9008833 to your computer and use it in GitHub Desktop.
//
// Arduino serial-interface for controlling the ws2812 leds. The serial interface is based on the
// Adalight protocol. The protocol is as follows:
// [prefix][led count][checksum][red, green, blue]*
// prefix := 'Ada'
// led count := number of leds - 1 (uint16_t big endian)
// checksum := led count high bit XOR led count low bit XOR 0x55 (uint8_t)
// red, green, blue := channel intensity [0-255] (uint8_t)
//
/// Definition of the maximum number of possible leds (depends on the available memory)
/// NOTE: The actual number of used leds is determined runtime in the adalight protocol
/// This number does not need to be modified to match the number of leds (as long as there
/// are less leds then the maximum allowed number)
#define MAX_LED_COUNT 512
/// Definition of the GPIO pin
#define BOOTSEQUENCE_IN_PIN 7
#define BOOTSEQUENCE_OUT_PIN 8
#define ARDUINO_LED_PIN 13
#define WS2812_PIN 2
/// Definition of the serial-baudrate
/// NOTE: 500kHz seemed to be the maximum (test at 1MHz failed)
#define serialRate 500000
/// FastSPI_LED2 includes
#include<FastLED.h>
/// The prefix for start sending led-data
static const uint8_t prefix[] = {'A', 'd', 'a'};
/// Array with led data to write
static CRGB _leds[MAX_LED_COUNT];
/// The controller for controlling the WS2812B strip on the configured PIN (default is GRB)
static WS2811Controller800Khz<WS2812_PIN, GRB> _controller;
///
/// Checks if BOOTSEQUENCE_IN_PIN is connected to BOOTSEQUENCE_OUT_PIN by making the OUT_PIN first
/// high and then low and checking if the IN_PIN follows these levels
///
/// @return True if the bootsequence is enabled by connecting IN_PIN and OUT_PIN
///
bool checkForBootSequence();
///
/// Runs a simple test sequence on the connected leds. This method can be used to check that the
/// leds are properly connected to the arduino.
///
void runTestSequence();
void setup()
{
// Set all the led values to zero
memset(_leds, 0, MAX_LED_COUNT * sizeof(CRGB));
// Initialise the LED controller
_controller.init();
// Run the optional boot sequence
if (checkForBootSequence())
{
runTestSequence();
}
// Switch all leds off (write black)
_controller.showColor(CRGB(0, 0, 0), MAX_LED_COUNT);
// Open the serial-connection
Serial.begin(serialRate);
// Send 'Ada' string to host
Serial.print("Ada\n");
}
void loop()
{
// Wait for first byte of 'Ada'
for(int i = 0; i < sizeof(prefix); ++i)
{
while (!Serial.available());
// Check next byte in Magic Word
if(prefix[i] != Serial.read())
return;
}
// Wait for highByte, lowByte, Checksum to be available
while(Serial.available() < 3);
// Read high and low byte and the checksum
int highByte = Serial.read();
int lowByte = Serial.read();
int checksum = Serial.read();
if (checksum != (highByte ^ lowByte ^ 0x55))
{
// Checksum check failed
return;
}
uint16_t ledCount = ((highByte & 0x00FF) << 8 | (lowByte & 0x00FF) ) + 1;
if (ledCount > MAX_LED_COUNT)
{
// Make sure that we do not read more data dan available in the buffer
ledCount = MAX_LED_COUNT;
}
// read the transmission data and set LED values
for (int i = 0; i < ledCount; i++)
{
// Wait for the next color spec to be available
while(Serial.available() < 3);
// Read the color spec
_leds[i].r = Serial.read();
_leds[i].g = Serial.read();
_leds[i].b = Serial.read();
}
// shows new values
_controller.show(_leds, ledCount);
}
bool checkForBootSequence()
{
// Configure the BOOTSEQUENCE pin as in- and out-put
pinMode(BOOTSEQUENCE_IN_PIN, INPUT);
pinMode(BOOTSEQUENCE_OUT_PIN, OUTPUT);
// Set the bootsequence out pin high
digitalWrite(BOOTSEQUENCE_OUT_PIN, HIGH);
// Read the value of the input pin (should be high)
int highValue = digitalRead(BOOTSEQUENCE_IN_PIN);
// Set the bootsequence out pin high
digitalWrite(BOOTSEQUENCE_OUT_PIN, LOW);
// Read the value of the input pin again (should be low)
int lowValue = digitalRead(BOOTSEQUENCE_IN_PIN);
// BOOTSEQUENCE_IN_PIN is only connected to BOOTSEQUENCE_OUT_PIN if the read values match the written values
return (highValue == HIGH && lowValue == LOW);
}
void runTestSequence()
{
// Switch the onboard led on
pinMode(BOOTSEQUENCE_OUT_PIN, OUTPUT);
digitalWrite(ARDUINO_LED_PIN, HIGH);
// Simple boot-sequence to check the arduino setup
_controller.showColor(CRGB::DarkRed, MAX_LED_COUNT);
delay(500);
_controller.showColor(CRGB::DarkGreen, MAX_LED_COUNT);
delay(500);
_controller.showColor(CRGB::DarkBlue, MAX_LED_COUNT);
delay(500);
// Switch the onboard led off
digitalWrite(ARDUINO_LED_PIN, LOW);
}
@tvdzwan
Copy link
Author

tvdzwan commented Feb 14, 2014

An arduino sketch for controlling a WS2812B led string connected to an Arduino nano, using the AdaLight serial protocol.
The code contains an extra test hook, which can be enabled by connecting pin 7 and 8. In this case the arduino will run a short color sequence across the led string when booting.

The code has been developed as part of the Hyperion project (https://github.com/tvdzwan/hyperion).

The source is released under MIT-License (see http://opensource.org/licenses/MIT).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment