Tuesday, March 28, 2017

Arduino Powered WS2812 LED Strips turned into 8x75 Array

I found out that there is a 512 LED limit on running continuous LED arrays from one output of the Arduino.  Then I discovered an alternate setup that can run 1200 addressable LED's from an Arduino.  The alternate method uses the parallel output mode to run 8 strings at the same time.  So far I am just testing the setup to see if it works.

This picture shows the  wiring, it is much easier than any other method of running the addressable LED strings.  Since I only have four strings of 150 LED's they are split in half to make 8 strings of 75 LED's each.

Here is my first test program running.  I changed the default array of patterns into some text.

I have improved the code to support longer strings:

It now has the ability to do 8 colors and use a character generator!

Here is the video on YouTube:


The sign now breaks down into sections that are each 40 inches long.  That is done with eight 3 pin plugs that are identical to what comes on the LED strips.

Here is the code so far:
// BOB Davis Enhanced Version for sending data to 8 Parallel WS2812 strings

// PORTD is Digital Pins 0-7 on the Uno change for other boards.
#define PIXEL_PORT  PORTD  // Port of the pin the pixels are connected to
#define PIXEL_DDR   DDRD   // Port of the pin the pixels are connected to

// These are the timing constraints taken mostly from the WS2812 datasheets
#define T0H  400    // Width of a 0 bit in ns
#define RES 6000    // Width of the low gap between bits to cause a frame to latch

// Here are some convience defines to generate actual CPU delays
#define NS_PER_SEC (1000000000L)  // Note that this has to be SIGNED
#define CYCLES_PER_SEC (F_CPU)
#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )

// Actually send the next set of 8 WS2812B encoded bits to the 8 pins.
// We must to drop to assembler to ensure proper timing
static inline __attribute__ ((always_inline)) void sendBitX8( uint8_t bits ) {
    const uint8_t onBits = 0xff;    // to send all bits on
    const uint8_t offBits = 0x00;   // to send all bits off
    asm volatile (
      "out %[port], %[onBits] \n\t"   // 1st step - send T0H high
      ".rept %[T0HCycles]     \n\t"   // Execute NOPs to delay
        "nop                  \n\t"
      ".endr                  \n\t"
      "out %[port], %[bits]   \n\t"   // Set the output bits to their values
      ".rept %[T0HCycles]     \n\t"   // Execute NOPs to delay
        "nop                  \n\t"
      ".endr                  \n\t"
      "out %[port], %[offBits]\n\t"   // last step set all bits low
      ::
      [port]    "I" (_SFR_IO_ADDR(PIXEL_PORT)),
      [bits]    "d" (bits),
      [onBits]   "d" (onBits),
      [offBits]   "d" (offBits),
      [T0HCycles] "I" (NS_TO_CYCLES(T0H) - 2)   // 1-bit width less overhead
    );
}

// Set default color for letters 1=red, 2=blue, 0=green
int color=0;

static inline void __attribute__ ((always_inline)) sendPixelRow( uint8_t row ) {
  // Send the bit 8 times down every row, each pixel is 8 bits each for R,G,B
  for (int c=0; c<3; c++) {
    for (int bit=0; bit<8; bit++){    
      if (color==c)sendBitX8( row );
      else sendBitX8( 0x00 );
    }
  }
}
 
byte cha[]={  // Can be hex or binary-easier to read
  0x80, 0x80, 0xff, 0x80, 0x80, 0x00, //T
  B11111111,  B10010001,  B10010001,  B10010001,  B10010001,  B00000000, //E
  B01100001,  B10010001,  B10010001,  B10010001,  B10001110,  B00000000, //S
  B10000000,  B10000000,  B11111111,  B10000000,  B10000000,  B00000000, //T
  B00000000,  B10000001,  B11111111,  B10000001,  B00000000,  B00000000, //I
  B11111111,  B01100000,  B00011000,  B00000110,  B11111111,  B00000000, //N
  B01111110,  B10000001,  B10000001,  B10000101,  B01100110,  B00000000, //G
  B00000000,  B01000001,  B11111111,  B00000001,  B00000000,  B00000000, //1
  B01000001,  B10000001,  B10000111,  B10011001,  B01100001,  B00000000, //2
  B10000001,  B10010001,  B10010001,  B10010001,  B01101110,  B00000000, //3
  B00011000,  B00101000,  B01001000,  B10001000,  B11111111,  B00000000, //4
  B11110001,  B10010001,  B10010001,  B10010001,  B10001110,  B00000000, //5
};

void setup() {
  PIXEL_DDR = 0xff;    // Set all row pins to output
}

void loop() {
  cli();           // No time for interruptions!
  for (int l=0; l<72; l++){  // 66 is number of bytes to send
    sendPixelRow(cha[l]);
  }
  sei();
  delay(10);      // Wait more than RESET timeout to latch into the LEDs
  return;
}

Monday, March 27, 2017

Changed my Car to a Chevrolet HHR

My Cobalt was hit by a deer and sustained over $1000 in damages.  For a 2007 with 165,000 miles that is essentially totaling the car.  SO I traded it in on a 2010 HHR that needs some minor repairs.
The hood was black (it had been in an accident) so I wire brushed it and put some white primer on it until I can afford to have it professionally painted.

One of the issues was strange noises coming from someplace in the back when going around corners.  I had already dug all the way down and removed the spare looking for the issue.  Maybe there was something in the gas tank?  The second time I took out the spare I looked behind the battery area and found a golf ball.  Before long I had pulled 6 golf balls out of that area.
 I decided to replace the air filter and discovered that changing the air filter on the HHR is a nightmare. You have to unplug the MAF sensor, and disconnect three hoses.  Then you can remove the air filter assembly and turn it over to remove 7 Torx screws.  Forget that.  I found this ad for a replacement for $75 on eBay.
The kit arrived in less than a week in a relatively small box.  It was only about one foot square in size.  But everything was there.

The changeover takes about 1 hour to complete.  Here is a before picture:
Here is an after picture:
I could not figure out how to "bend" the included metal strap to hold the air filter in place so I used some wire ties instead.  The oil fill spout extension can be removed.  The cap will fit directly on the engine.  The spark plugs are next to be replaced now that I can actually find them....

The HHR did not come with a back seat.  It had the metal frame that was designed for use with storage bins.  The storage bins list for $700 from Chevy!  So I made my own storage area using some plywood.

I will need to make some wood trim to go around the outside edge.  Here is the view from the back side.


Thursday, March 2, 2017

Arduino Powered F450 Quadcopter/Drone

My next project and book will be on Arduino powered Quadcopters.  So far all I have assembled is the frame.  This is a DJI F450 Quadcopter with A2212 motors.


Soldering the connectors on the motors is not easy!  You have to use an alligator clip to hold the connector in place.  Find the hole in the side of the connector and use it to get the soldering iron into the center.  This requires a fine soldering iron tip.  Fill the center with solder. Stick the wire into the hot solder.  I also bent the wire over so it fits tightly first of all.  I should have stripped some more insulation off first.
I have mounted the Arduino on the drone and added a sensor shield to connect to the Receiver and the ESC's.  Next to add the 6 axis accelerometer and gyroscope MPU-6050 module.  So far I can control it and even tested out the motors.  

This is the video of its first very short flight....

A successful flight - well almost.