Commits

Christopher De Vries committed bfadbcf

Initial commit of beaglebone library. Still working on making it awesome.

Comments (0)

Files changed (6)

+syntax: glob
+*~
+*.swp
+.git
+*.o
+
+.DS_Store
+CFLAGS = -O3
+CC = gcc
+BUNDLE = Makefile tclled.h tclled.c tcl_speedtest.c 
+VERSION = 0.5
+ARCHIVE = beagle-tcl
+LIBS = -lm
+
+all: tcl_speedtest 
+
+archive: $(BUNDLE)
+	mkdir $(ARCHIVE)-$(VERSION)
+	cp $(BUNDLE) $(ARCHIVE)-$(VERSION)/
+	tar cvfz $(ARCHIVE)-$(VERSION).tar.gz $(ARCHIVE)-$(VERSION)
+	rm -rf $(ARCHIVE)-$(VERSION)
+
+clean:
+	$(RM) *.o
+	$(RM) $(ARCHIVE)-$(VERSION).tar.gz
+
+tcl_speedtest: tcltest.o tclled.o
+	$(CC) $(CFLAGS) $(LIBS) -o tcltest $^
+
+tcl_speedtest.o: tclled.h tcltest.c
+
+tclled.o: tclled.h tclled.c
+Total Control Lighting (p9813) BeagleBone library
+Copyright 2012 Christopher De Vries
+www.idolstarastronomer.com
+
+INTRODUCTION
+
+This library is designed to help you get started using the Total Control
+Lighting RGB LED pixels from www.coolneon.com on your BeagleBone.
+This library should work on any linux platform in which the spidev kernel
+module has been included.
+
+BACKGROUND
+
+The p9813 chip operates with a voltage between 5V and 6.5V. In addition to V+
+and Ground inputs, the chip also has a clock input, serial data input, clock
+output, and serial data output. The p9813 chip has a maximum serial clock rate
+of 15 MHz. 
+
+The p9813 accepts data from the Serial Data in on the rising edge of the
+serial input clock signal. It will read one bit per tick. A frame of 4 bytes
+(32 bits) is required to set the pixel color. Each byte is sent on MSB order.
+The first byte is a flag byte, the second byte is the blue data, the third is
+green, and the fourth is red. Each color is represented as an 8 bit unsigned
+integer running from 0 (completely off) to 255 (completely on). The flag byte
+is made up of the following bits (from highest order, or most significant,
+down):
+
+Bit 7: Always 1
+Bit 6: Always 1
+Bit 5: Inverse of blue bit 7
+Bit 4: Inverse of blue bit 6
+Bit 3: Inverse of green bit 7
+Bit 2: Inverse of green bit 6
+Bit 1: Inverse of red bit 7
+Bit 0: Inverse of red bit 6
+
+As an example, the following sample of C code calculates the flag bit (this is
+included in the library):
+
+    uint8_t make_flag(uint8_t red, uint8_t green, uint8_t blue) {
+      uint8_t flag;
+
+      flag =  (red&0xc0)>>6;
+      flag |= (green&0xc0)>>4;
+      flag |= (blue&0xc0)>>2;
+
+      return ~flag;
+    }
+
+Once a pixel's color is set, it will pass along subsequent 32 bit frames via
+its clock out and serial data out ports. 
+
+To initialize a p9813 chip to receive a new color you must send a frame
+composed entirely of 0s (32 bits of 0s). In order to display the colors you
+have sent to a chip, you must also send a frame of 32 bits of 0s. It appears
+as though you actually must send more than one frame of 0s if the chain of
+pixels is long. This library will send 1 frame of 0s to initialize the chip
+prior to sending out pixel data and 2 frames of 0s to display the pixels
+after.
+
+The BeagleBone's processor has built-in support for SPI, making it very fast.
+In order to use this capability from userspace linux programs, you must use a
+linux kernel with the spidev module built in. The Angstrom linux BeagleBone
+demo image (available at
+http://downloads.angstrom-distribution.org/demo/beaglebone/) starting with the
+June 18, 2012 image have spidev compiled in. I have done my testing with the
+June 18, 2012 image available at
+http://downloads.angstrom-distribution.org/demo/beaglebone/archive/Angstrom-Cloud9-IDE-GNOME-eglibc-ipk-v2012.05-beaglebone-2012.06.18.img.xz
+
+HARDWARE
+
+The Total Control Lighting pixel strands, sold by coolneon.com, have 4 wires
+running from pixel to pixel. These wires are color coded in the following way:
+
+Red: Vcc (+5 to +6.5 V)
+White: Data
+Green: Clock
+Blue: Ground
+
+Each pixel has an input set of wires and an output set. Usually there is an
+arrow indicating the direction on the casing of the LED/chip unit. It is more
+convenient to use the connectors which you can purchase from coolneon.com. You
+will need the female connector to send data to the pixels. The wire coloring
+on the connector is slightly different:
+
+Red: Vcc (+5 to +6.5 V)
+Green: Data
+Yellow: Clock
+Blue (or Black): Ground
+
+It is useful, though not required, to purchase the "T-connectors" sold at
+coolneon.com. The T-connectors pass through the Data and Clock lines, but
+splice the Vcc and Ground lines to a 2.5mm center positive barrel connector.
+We typically find that we provide power by using a T-connector every 100
+pixels or so (depending on the application). 
+
+On the BeagleBone the following pins are configured for SPI:
+
+P9 Header Pin 30: Data out (SPI1_D1)
+P9 Header Pin 31: Clock out (SPI1_SCLK)
+
+You should also hook up a ground wire from the pixels and the power supply for
+the pixels to P9 Header Pin 1 or 2. A typical wiring diagram is shown below:
+
+
++-----------------------------+
+|                         5 V +---------+
+| Pixel Power Source          |         |
+|                         GND +----+    |
++-----------------------------+    |    |
+                                   |    |     +-----------------------------+
++-----------------------------+    |    +-----+ V+                          |
++                   P9 Pin 1  +----+----------+ GND        TCL Pixel        |
++ BeagleBone        P9 Pin 30 +---------------+ Data                        |
++                   P9 Pin 31 +---------------+ Clock                       |
++-----------------------------+               +-----------------------------+
+
+LIBRARY
+
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include "tclled.h"
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+static const char *device = "/dev/spidev2.0";
+static const int leds = 1250;
+static const int frames = 10000;
+
+int main(int argc, char *argv[]) {
+  tcl_buffer buf;
+  int fd;
+  int ret;
+  int i, j;
+  tcl_color *p;
+  struct timeval tv_start, tv_end, tv_diff;
+  struct timezone tz;
+  double fps;
+
+  tz.tz_minuteswest=0;
+  tz.tz_dsttime=0;
+
+  ret = gettimeofday(&tv_start,&tz);
+  if(ret==-1) {
+    fprintf(stderr,"Error %d: %s\n",errno, strerror(errno));
+    exit(1);
+  }
+
+  fd = open(device,O_WRONLY);
+  if(fd<0) {
+    fprintf(stderr, "Can't open device.\n");
+    exit(1);
+  }
+
+  ret=spi_init(fd);
+  if(ret==-1) {
+    fprintf(stderr,"error=%d, %s\n", errno, strerror(errno));
+    exit(1);
+  }
+
+  tcl_init(&buf,leds);
+
+  for(i=0;i<frames;i++) {
+    p = buf.pixels;
+    for(j=0;j<leds;j++) {
+      if(j==i%leds) {
+        write_color(p,0x00,0x00,0xff);
+      }
+      else {
+        write_color(p,0x00,0x00,0x00);
+      }
+      p++;
+    }
+    send_buffer(fd,&buf);
+    /* usleep(1000000); */
+  }
+
+  ret = gettimeofday(&tv_end,&tz);
+  if(ret==-1) {
+    fprintf(stderr,"Error %d: %s\n",errno, strerror(errno));
+    exit(1);
+  }
+
+  tv_diff.tv_sec=tv_end.tv_sec-tv_start.tv_sec;
+  tv_diff.tv_usec=tv_end.tv_usec-tv_start.tv_usec;
+
+  while(tv_diff.tv_usec<0) {
+    tv_diff.tv_usec+=1000000;
+    tv_diff.tv_sec-=1;
+  }
+
+  printf("Time elapsed: %d sec and %d microseconds.\n",tv_diff.tv_sec,tv_diff.tv_usec);
+
+  fps = (double)frames/((double)tv_diff.tv_sec+(double)tv_diff.tv_usec/1000000.0);
+
+  printf("%.2f frames per second.\n",fps);
+
+  tcl_free(&buf);
+  close(fd);
+  return 0;
+}
+#include "tclled.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+#include <errno.h>
+#include <math.h>
+
+void write_frame(tcl_color *p, uint8_t flag, uint8_t red, uint8_t green, uint8_t blue);
+uint8_t make_flag(uint8_t red, uint8_t greem, uint8_t blue);
+ssize_t write_all(int filedes, const void *buf, size_t size);
+
+static uint8_t gamma_table_red[256];
+static uint8_t gamma_table_green[256];
+static uint8_t gamma_table_blue[256];
+
+void tcl_init(tcl_buffer *buf, int leds) {
+  buf->leds = leds;
+  buf->size = (leds+3)*sizeof(tcl_color);
+  buf->buffer = (tcl_color*)malloc(buf->size);
+  if(buf->buffer==NULL) {
+    fprintf(stderr, "ERROR: Unable to allocate sufficient memory.");
+    exit(1);
+  }
+
+  buf->pixels = buf->buffer+1;
+
+  write_frame(buf->buffer,0x00,0x00,0x00,0x00);
+  write_frame(buf->pixels+leds,0x00,0x00,0x00,0x00);
+  write_frame(buf->pixels+leds+1,0x00,0x00,0x00,0x00);
+}
+
+int spi_init(int filedes) {
+  int ret;
+  const uint8_t mode = SPI_MODE_0;
+  const uint8_t bits = 8;
+  const uint32_t speed = 15000000;
+
+  ret = ioctl(filedes,SPI_IOC_WR_MODE, &mode);
+  if(ret==-1) {
+    return -1;
+  }
+
+  ret = ioctl(filedes,SPI_IOC_WR_BITS_PER_WORD, &bits);
+  if(ret==-1) {
+    return -1;
+  }
+
+  ret = ioctl(filedes,SPI_IOC_WR_MAX_SPEED_HZ,&speed);
+  if(ret==-1) {
+    return -1;
+  }
+
+  return 0;
+}
+
+void write_color(tcl_color *p, uint8_t red, uint8_t green, uint8_t blue) {
+  uint8_t flag;
+
+  flag = make_flag(red,green,blue);
+  write_frame(p,flag,red,green,blue);
+}
+
+int send_buffer(int filedes, tcl_buffer *buf) {
+  int ret;
+
+  ret = (int)write_all(filedes,buf->buffer,buf->size);
+  return ret;
+}
+
+void tcl_free(tcl_buffer *buf) {
+  free(buf->buffer);
+  buf->buffer=NULL;
+  buf->pixels=NULL;
+}
+
+void write_frame(tcl_color *p, uint8_t flag, uint8_t red, uint8_t green, uint8_t blue) {
+  p->flag=flag;
+  p->blue=blue;
+  p->green=green;
+  p->red=red;
+}
+
+uint8_t make_flag(uint8_t red, uint8_t green, uint8_t blue) {
+  uint8_t flag;
+
+  flag =  (red&0xc0)>>6;
+  flag |= (green&0xc0)>>4;
+  flag |= (blue&0xc0)>>2;
+
+  return ~flag;
+}
+
+ssize_t write_all(int filedes, const void *buf, size_t size) {
+  ssize_t buf_len = (ssize_t)size;
+  size_t attempt = size;
+  ssize_t result;
+
+  while(size>0) {
+    result = write(filedes,buf,attempt);
+    if(result<0) {
+      if(errno==EINTR) continue;
+      else if(errno==EMSGSIZE) {
+        attempt = attempt/2;
+        result = 0;
+      }
+      else {
+        return result;
+      }
+    }
+    buf+=result;
+    size-=result;
+    if(attempt>size) attempt=size;
+  }
+
+  return buf_len;
+}
+
+void set_gamma(double gamma_red, double gamma_green, double gamma_blue) {
+  int i;
+  
+  for(i=0;i<256;i++) {
+    gamma_table_red[i] = (uint8_t)(pow(i/255.0,gamma_red)*255.0+0.5);
+    gamma_table_green[i] = (uint8_t)(pow(i/255.0,gamma_green)*255.0+0.5);
+    gamma_table_blue[i] = (uint8_t)(pow(i/255.0,gamma_blue)*255.0+0.5);
+  }
+}
+
+void write_gamma_color(tcl_color *p, uint8_t red, uint8_t green, uint8_t blue) {
+  uint8_t flag;
+  uint8_t gamma_corrected_red = gamma_table_red[red];
+  uint8_t gamma_corrected_green = gamma_table_green[green];
+  uint8_t gamma_corrected_blue = gamma_table_blue[blue];
+
+  flag = make_flag(gamma_corrected_red,gamma_corrected_green,gamma_corrected_blue);
+  write_frame(p,flag,gamma_corrected_red,gamma_corrected_green,gamma_corrected_blue);
+}
+#ifndef _TCLLED_H
+#define _TCLLED_H
+#include <stdint.h>
+#include <linux/types.h>
+#include <stdlib.h>
+
+typedef struct _tcl_color {
+  uint8_t flag;
+  uint8_t blue;
+  uint8_t green;
+  uint8_t red;
+} tcl_color;
+
+typedef struct _tcl_buffer {
+  int leds; /* number of LEDS */
+  size_t size; /* size of buffer */
+  tcl_color *buffer; /* pointer to buffer memory */
+  tcl_color *pixels; /* pointer to start of pixels */
+} tcl_buffer;
+
+void tcl_init(tcl_buffer *buf, int leds);
+int spi_init(int filedes);
+void write_color(tcl_color *p, uint8_t red, uint8_t green, uint8_t blue);
+int send_buffer(int filedes, tcl_buffer *buf);
+void tcl_free(tcl_buffer *buf);
+void set_gamma(double gamma_red, double gamma_green, double gamma_blue);
+void write_gamma_color(tcl_color *p, uint8_t red, uint8_t green, uint8_t blue);
+
+#endif /*!_TCLLED_H*/
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.