Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save kauailabs/29496c8b4e069575e9e77d1985d54b1a to your computer and use it in GitHub Desktop.

Select an option

Save kauailabs/29496c8b4e069575e9e77d1985d54b1a to your computer and use it in GitHub Desktop.
/*
* The ledarray_onewire example demonstrates controlling an array of 30 LEDs controlled using the
* "one wire" protocol found in the WS2811, SK6812 and WS2812 LED controllers. Otherwise known as
* "neopixel" arrays, each LED is serially daisy-chained, and the Red, Green and Blue (RGB) values
* for each pixel can range of 0 (off) to 255 (fully on). The values are transmitted via a series
* of pulses, which have different lengths depending whether a "one" or a "zero" symbol is being
* communicated. Once all LED values have been transmitted, a reset signal is transmitted (comprised
* of holding the signal low for at least a "reset time period".
*
* Note that each controller can specify a slightly different duration for the "one" and "zero" symbols,
* as specified in the controller datasheet. The LEDArray_OneWireConfig object may be configured
* to specify these values. In the example below, the timing values for the SK6812 are used.
*
* By default, the symbol frequency is 800k symbols/second (all neopixel devices support this frequency).
* The underlying bit-timing pulse frequency is equal to the symbol frequency * 10. This results in a
* minimum granularity in pulse time of 1 second / 8,000,000 = 125 nanoseconds. If non-default values
* are specified within the LEDArray_OneWireConfig object, they will be rounded to the nearest 125 nanosecond period.
*
* Currently, VMX-pi only supports "One Wire" LED Arrays on VMXChannelIndex 31. Internally, data is transmitted
* to the array using the Raspberry Pi "SPI" resource, which internally uses hardware-controlled DMA transfers
* when sending bits to the LEDArray. Note that by default, the Raspberry PI SPI Transmit Buffer size is 4096.
* This value sets a limit on the maximum number of "pixels" in the LED Array, per the following calculation:
*
* BytesPerPixel = 10 bits/symbol * 3 colors * 8 symbols/color = 240 bits = 30 bytes
* ResetOverHeadBytes = (55 microseconds * 800Khz * 10 bits/symbol) / 1000000 = 440 bits = 55 bytes
* MaxNumPixels = (SPIBufferSize - ResetOverHeadBytes) / BytesPerPixel = (4096 - 55) / 30 bytes = 134
*
* If for some reason this maximum must be exceeded, the default maximum SPI transfer size can be
* increased (up to a maximum of 65536 bytes) by editing the Raspberry Pi /boot/cmdline.txt file. For example, to set the SPI transfer
* size to 65536 bytes, add "spidev.bufsize=65536" to the first line of text in the /boot/cmdline.txt file
* and then reboot the Raspberry Pi. Note when editing this file that errors in this file can prohibit
* the Raspberry Pi from booting correctly (so be careful!) and that /boot/cmdline.txt should contain only a single line of text.
*
* In this example, a continuous up/down ramp of purple values is output to the array.
*/
#include <stdio.h> /* printf() */
#include <string.h> /* memcpy() */
#include <inttypes.h>
#include "VMXPi.h"
void DisplayVMXError(VMXErrorCode vmxerr) {
const char *p_err_description = GetVMXErrorString(vmxerr);
printf("VMXError %d: %s\n", vmxerr, p_err_description);
}
int main(int argc, char *argv[])
{
bool realtime = true;
uint8_t update_rate_hz = 50;
VMXPi vmx(realtime, update_rate_hz);
try {
VMXErrorCode vmxerr;
VMXResourceHandle ledarray_res_handle;
VMXChannelInfo ledarray_channel_info = VMXChannelInfo(vmx.getIO().GetSoleChannelIndex(VMXChannelCapability::LEDArray_OneWire), VMXChannelCapability::LEDArray_OneWire);
// NOTE: The Raspberry PI SPI Buffer size may need to be increased if the number of LEDs
// exceeds the current buffer size. See notes above.
LEDArray_OneWireConfig ledarray_cfg(30); // Configure LED Array to be 30 pixels long
// Configure "OneWire" protocol timing for the SK6812, based on datasheet specifications
// NOTE: Reasonable defaults for the following are provided, so this detailed configuration
// may not be necessary.
ledarray_cfg.SetResetWaitTimeMicroseconds(80);
ledarray_cfg.SetOneSymbolHighTimeNanoseconds(600);
ledarray_cfg.SetZeroSymbolHighTimeNanoseconds(300);
if (!vmx.io.ActivateSinglechannelResource(ledarray_channel_info, &ledarray_cfg, ledarray_res_handle, &vmxerr)) {
printf("Failed to Activate LEDArray_OneWire Resource.\n");
DisplayVMXError(vmxerr);
} else {
printf("Successfully Activated LEDArray_OneWire Resource Resource with VMXChannel %d\n",
ledarray_channel_info.index);
}
LEDArrayBufferHandle buffer_handle;
if (vmx.io.LEDArrayBuffer_Create(ledarray_cfg.n_pixels, buffer_handle, &vmxerr)) {
if (!vmx.io.LEDArray_SetBuffer(ledarray_res_handle, buffer_handle, &vmxerr)) {
printf("Error setting LED Array buffer into LEDArray Driver Resource\n");
DisplayVMXError(vmxerr);
} else {
printf("Successfully created LEDArray buffer and registered it with the LEDArray Driver.\n");
bool increasing = false;
int red = 255;
for (int i = 0; i < 10000; i++) {
for (int i = 0; i < ledarray_cfg.n_pixels; i++) {
int green = 0;
int blue = red;
if (!vmx.io.LEDArrayBuffer_SetRGBValue(buffer_handle, i, red, green, blue, &vmxerr)) {
printf("Error setting RGB Value to LED Array buffer for index %d\n", i);
DisplayVMXError(vmxerr);
}
int curr_red, curr_green, curr_blue;
if (!vmx.io.LEDArrayBuffer_GetRBGValue(buffer_handle, i, curr_red, curr_green, curr_blue, &vmxerr)) {
printf("Error getting RGB Value from LED Array buffer for index %d\n", i);
DisplayVMXError(vmxerr);
} else {
if ((curr_red != red) || (curr_green != green) || (curr_blue != blue)) {
printf("Readback of RGB values from LED Array buffer at index %d returned unexpected values.\n", i);
}
}
}
if (increasing) {
if (red < 255) {
red+= 2;
} else {
increasing = false;
}
}
if (!increasing) {
if (red > 20) {
red-= 2;
} else {
increasing = true;
}
}
if (!vmx.io.LEDArray_Render(ledarray_res_handle, &vmxerr)) {
printf("Error Rendering updates via LEDArray Driver Resource\n");
DisplayVMXError(vmxerr);
break;
} else {
// Increasing the delay here will slow the overall refresh rate,
// but may decrease overall cpu usage.
vmx.time.DelayMilliseconds(25);
}
}
}
if (!vmx.io.LEDArrayBuffer_Delete(buffer_handle, &vmxerr)) {
printf("Error deleting LEDArray_OneWire Buffer.");
DisplayVMXError(vmxerr);
} else {
printf("Successfully Deleted LEDArray_OneWire Buffer\n");
}
} else {
printf("Error creating LEDArray_OneWire Buffer.");
DisplayVMXError(vmxerr);
}
if (!vmx.io.DeallocateResource(ledarray_res_handle, &vmxerr)) {
printf("Error deallocating LEDArray_OneWire resource.\n");
DisplayVMXError(vmxerr);
} else {
printf("Successfully deallocated LED Array resource\n");
}
}
catch(const std::exception& ex){
printf("Caught exception: %s", ex.what());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment