0

Can't Daisychain DotStar matrix?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Can't Daisychain DotStar matrix?

by roach374 on Tue Feb 06, 2018 10:05 pm

I took the demo code from the "Sipping power" tutorial (https://learn.adafruit.com/sipping-powe ... /demo-code ) , and made it work with one Dotstar 8x8 matrix panel. It works great, no problems. When I went to daisy chain another panel, I can't get either panel to light up now.

I'm providing adequate power, but no LEDs are lighting up! What am I doing wrong?

Code: Select all | TOGGLE FULL SIZE
// Sketch to accompany "Sipping Power With NeoPixels" guide.  Designed for
// Adafruit Circuit Playground but could be adapted to other projects.

#include <SPI.h>
#include <Adafruit_DotStarMatrix.h>

// GLOBAL VARIABLES --------------------------------------------------------

// This bizarre construct isn't Arduino code in the conventional sense.
// It exploits features of GCC's preprocessor to generate a PROGMEM
// table (in flash memory) holding an 8-bit unsigned sine wave (0-255).
const int _SBASE_ = __COUNTER__ + 1; // Index of 1st __COUNTER__ ref below
#define _S1_ (sin((__COUNTER__ - _SBASE_) / 128.0 * M_PI) + 1.0) * 127.5 + 0.5,
#define _S2_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ // Expands to 8 items
#define _S3_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ // Expands to 64 items
const uint8_t PROGMEM sineTable[] = { _S3_ _S3_ _S3_ _S3_ }; // 256 items

// Similar to above, but for an 8-bit gamma-correction table.
#define _GAMMA_ 2.6
const int _GBASE_ = __COUNTER__ + 1; // Index of 1st __COUNTER__ ref below
#define _G1_ pow((__COUNTER__ - _GBASE_) / 255.0, _GAMMA_) * 255.0 + 0.5,
#define _G2_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ // Expands to 8 items
#define _G3_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ // Expands to 64 items
const uint8_t PROGMEM gammaTable[] = { _G3_ _G3_ _G3_ _G3_ }; // 256 items

// These are used for 'debouncing' the left & right button inputs,
// for switching between modes.
// boolean  prevStateLeft, prevStateRight;
// uint32_t lastChangeTimeLeft = 0, lastChangeTimeRight = 0;
// #define  DEBOUNCE_MS 15 // Button debounce time, in milliseconds

// These are used in estimating (very approximately) the current draw of
// the board and NeoPixels.  BASECURRENT is the MINIMUM current (in mA)
// used by the entire system (microcontroller board plus NeoPixels) --
// keep in mind that even when "off," NeoPixels use a tiny amount of
// current (a bit under 1 milliamp each).  LEDCURRENT is the maximum
// additional current PER PRIMARY COLOR of ONE NeoPixel -- total current
// for an RGB NeoPixel could be up to 3X this.  The '3535' NeoPixels on
// Circuit Playground are smaller and use less current than the more
// common '5050' type used in NeoPixel strips and shapes.
#define BASECURRENT 10
#define LEDCURRENT  13.3 // Try using 18 for '5050' NeoPixels
#define BRIGHTNESS  32
uint8_t  frame = 0;    // Frame count, results displayed every 256 frames
uint32_t sum   = 0;    // Cumulative current, for calculating average
uint8_t *pixelPtr;     // -> NeoPixel color data

void mode_off();
void mode_white_max();
void mode_white_half_duty();
void mode_white_half_perceptual();
void mode_primaries();
void mode_colorwheel();
void mode_colorwheel_gamma();
void mode_half();
void mode_sparkle();
void mode_marquee();
void mode_sine();
void mode_sine_gamma();
void mode_sine_half_gamma();

// This array lists each of the display/animation drawing functions
// (which appear later in this code) in the order they're selected with
// the right button.  Some functions appear repeatedly...for example,
// we return to "mode_off" at several points in the sequence.
void (*renderFunc[])(void) {
  mode_off, // Starts here, with LEDs off
  mode_white_max, mode_white_half_duty , mode_white_half_perceptual, mode_off,
  mode_primaries, mode_colorwheel, mode_colorwheel_gamma,
  mode_half, mode_sparkle,
  mode_marquee, mode_sine, mode_sine_gamma, mode_sine_half_gamma
};
const int N_MODES = (sizeof(renderFunc) / sizeof(renderFunc[0]));
uint8_t mode = 0; // Index of current mode in table
long int lastChangeTime;
#define MODE_CHANGE_TIME_MS 5000    //milliseconds between mode changes.

Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 16, 8,
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);


// SETUP FUNCTION -- RUNS ONCE AT PROGRAM START ----------------------------

void setup() {
  matrix.begin();
  matrix.setBrightness(BRIGHTNESS); // NeoPixels at full brightness
  pixelPtr = matrix.getPixels();

  Serial.begin(19200);

  // prevStateLeft  = matrix.leftButton(); // Initial button states
  // prevStateRight = matrix.rightButton();
}

// LOOP FUNCTION -- RUNS OVER AND OVER FOREVER -----------------------------

void loop() {

  // Read and debounce left/right buttons
  uint32_t t = millis();
  // if((t - lastChangeTimeLeft) >= DEBOUNCE_MS) {
  //   boolean b = matrix.leftButton();
  //   if(b != prevStateLeft) {             // Left button state changed?
  //     prevStateLeft      = b;
  //     lastChangeTimeLeft = t;
  //     if(b) {                            // Left button pressed?
  //       if(mode) mode--;                 // Go to prior mode
  //       else     mode = N_MODES - 1;     // or "wrap around" to last mode
  //       frame = sum = 0;                 // Reset power calculation
  //     }
  //   }
  // }
  // if((t - lastChangeTimeRight) >= DEBOUNCE_MS) {
  //   boolean b = matrix.rightButton();
  //   if(b != prevStateRight) {            // Right button state changed?
  //     prevStateRight      = b;
  //     lastChangeTimeRight = t;
  //     if(b) {                            // Right button pressed?
  //       if(mode < (N_MODES-1)) mode++;   // Advance to next mode
  //       else                   mode = 0; // or "wrap around" to start
  //       frame = sum = 0;                 // Reset power calc
  //     }
  //   }
  // }

  //for now, just change modes every ten seconds or something.
  if((t-lastChangeTime) >= MODE_CHANGE_TIME_MS){
    mode = (mode+1) % N_MODES;
    lastChangeTime=t;
  }

  (*renderFunc[mode])();          // Render one frame in current mode
  matrix.show(); // and update the NeoPixels to show it

  // Accumulate total brightness value for all NeoPixels (assumes RGB).
  for(uint8_t i=0; i<matrix.numPixels() * 3; i++) {
    sum += pixelPtr[i];
  }
  if(!++frame) { // Every 256th frame, estimate & print current
    Serial.print(BASECURRENT + (sum * (LEDCURRENT * BRIGHTNESS / 256) + 32640) / 65280);
    Serial.println(" mA");
    sum = 0; // Reset pixel accumulator
  }
}

// RENDERING FUNCTIONS FOR EACH DISPLAY/ANIMATION MODE ---------------------

// All NeoPixels off
void mode_off() {
  matrix.clear();
}

// All NeoPixels on at max: white (R+G+B) at 100% duty cycle
void mode_white_max() {
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, 0xFFFFFF);
  }
}

// All NeoPixels on at 50% duty cycle white.  Numerically speaking,
// this is half power, but perceptually it appears brighter than 50%.
void mode_white_half_duty() {
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, 0x7F7F7F);
  }
}

// All NeoPixels on at 50% perceptial brightness, using gamma table lookup.
// Though it visually appears to be about half brightness, numerically the
// duty cycle is much less, a bit under 20% -- meaning "half brightness"
// can actually be using 1/5 the power!
void mode_white_half_perceptual() {
  uint32_t c = pgm_read_byte(&gammaTable[127]) * 0x010101;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, c);
  }
}

// Cycle through primary colors (red, green, blue), full brightness.
// Because only a single primary color within each NeoPixel is turned on
// at any given time, this uses 1/3 the power of the "white max" mode.
void mode_primaries() {
  uint32_t c;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    // This animation (and many of the rest) pretend spatially that there's
    // 12 equally-spaced NeoPixels, though in reality there's only 10 with
    // gaps at the USB and battery connectors.
    uint8_t j = i + (i > 4);     // Mind the gap
    j = ((millis() / 100) + j) % 12;
    if(j < 4)      c = 0xFF0000; // Bed
    else if(j < 8) c = 0x00FF00; // Green
    else           c = 0x0000FF; // Blue
    matrix.setPixelColor(i, c);
  }
}

// HSV (hue-saturation-value) to RGB function used for the next two modes.
uint32_t hsv2rgb(int32_t h, uint8_t s, uint8_t v, boolean gc=false) {
  uint8_t n, r, g, b;

  // Hue circle = 0 to 1530 (NOT 1536!)
  h %= 1530;           // -1529 to +1529
  if(h < 0) h += 1530; //     0 to +1529
  n  = h % 255;        // Angle within sextant; 0 to 254 (NOT 255!)
  switch(h / 255) {    // Sextant number; 0 to 5
   case 0 : r = 255    ; g =   n    ; b =   0    ; break; // R to Y
   case 1 : r = 254 - n; g = 255    ; b =   0    ; break; // Y to G
   case 2 : r =   0    ; g = 255    ; b =   n    ; break; // G to C
   case 3 : r =   0    ; g = 254 - n; b = 255    ; break; // C to B
   case 4 : r =   n    ; g =   0    ; b = 255    ; break; // B to M
   default: r = 255    ; g =   0    ; b = 254 - n; break; // M to R
  }

  uint32_t v1 =   1 + v; // 1 to 256; allows >>8 instead of /255
  uint16_t s1 =   1 + s; // 1 to 256; same reason
  uint8_t  s2 = 255 - s; // 255 to 0

  r = ((((r * s1) >> 8) + s2) * v1) >> 8;
  g = ((((g * s1) >> 8) + s2) * v1) >> 8;
  b = ((((b * s1) >> 8) + s2) * v1) >> 8;
  if(gc) { // Gamma correct?
    r = pgm_read_byte(&gammaTable[r]);
    g = pgm_read_byte(&gammaTable[g]);
    b = pgm_read_byte(&gammaTable[b]);
  }
  return ((uint32_t)r << 16) | ((uint16_t)g << 8) | b;
}

// Rotating color wheel, using 'raw' RGB values (no gamma correction).
// Average current use is about 1/2 of the max-all-white case.
void mode_colorwheel() {
  uint32_t t = millis();
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    matrix.setPixelColor(i,
      hsv2rgb(t + j * 1530 / 12, 255, 255, false));
  }
}

// Color wheel using gamma-corrected values.  Current use is slightly less
// than the 'raw' case, but not tremendously so, as only 1/3 of pixels at
// any time are in transition cases (else 100% on or off).
void mode_colorwheel_gamma() {
  uint32_t t = millis();
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    matrix.setPixelColor(i,
      hsv2rgb(t + j * 1530 / 12, 255, 255, true));
  }
}

// Cycle with half the pixels on, half off at any given time.
// Simple idea.  Half the pixels means half the power use.
void mode_half() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = t + i * 256 / matrix.numPixels();
    j = (j >> 7) * 255;
    matrix.setPixelColor(i, j * 0x010000);
  }
}

// Blue sparkles.  Randomly turns on ONE pixel at a time.  This demonstrates
// minimal power use while still doing something "catchy."  And because it's
// a primary color, power use is even minimal-er (see 'primaries' above).
void mode_sparkle() {
  static uint8_t randomPixel = 0;
  if(!(frame & 0x7F)) {              // Every 128 frames...
    matrix.clear(); // Clear pixels
    uint8_t r;
    do {
      r = random(matrix.numPixels());                // Pick a new random pixel
    } while(r == randomPixel);       // but not the same as last time
    uint32_t c = random(0xFFFFFF);
    randomPixel = r;                 // Save new random pixel index
    matrix.setPixelColor(randomPixel, c);
  }
}

// Simple on-or-off "marquee" animation w/ about 50% of pixels lit at once.
// Not much different than the 'half' animation, but provides a conceptual
// transition into the examples that follow.
void mode_marquee() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = (t + j * 256 / 12) & 0xFF;
    k = ((k >> 6) & 1) * 255;
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Sine wave marquee, no gamma correction.  Avg. overall duty cycle is 50%,
// and combined with being a primary color, uses about 1/6 the max current.
void mode_sine() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Sine wave with gamma correction.  Because nearly all the pixels have
// "in-between" values (not 100% on or off), there's considerable power
// savings to gamma correction, in addition to looking more "correct."
void mode_sine_gamma() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]);
    k = pgm_read_byte(&gammaTable[k]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Perceptually half-brightness gamma-corrected sine wave.  Sometimes you
// don't need things going to peak brightness all the time.  Combined with
// gamma and primary color use, it's super effective!
void mode_sine_half_gamma() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]) / 2;
    k = pgm_read_byte(&gammaTable[k]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Thu Feb 08, 2018 4:33 pm

Bumping this, since I'm still not able to get more than one of these things working together. Anyone got any bright (pun intended) ideas?

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by Arudinne on Thu Feb 08, 2018 7:10 pm

Where are your clock and data pins defined?

You have:
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 16, 8,
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);

The Matrix test code is looking for:

Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
  8, 8, DATAPIN, CLOCKPIN,
  DS_MATRIX_TOP     + DS_MATRIX_RIGHT +
  DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
  DOTSTAR_BRG);


https://github.com/adafruit/Adafruit_Do ... ixtest.pde

Does the matrix test above code work with both?

Arudinne
 
Posts: 281
Joined: Sun Mar 19, 2017 9:36 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Fri Feb 09, 2018 2:27 pm

Arudinne wrote:Where are your clock and data pins defined?

You have:
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 16, 8,
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);

The Matrix test code is looking for:

Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
  8, 8, DATAPIN, CLOCKPIN,
  DS_MATRIX_TOP     + DS_MATRIX_RIGHT +
  DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
  DOTSTAR_BRG);


https://github.com/adafruit/Adafruit_Do ... ixtest.pde

Does the matrix test above code work with both?


Adafruit_DotStarMatrix has an alternative constructor, for use with SPI, where no pins are defined (it just uses the SPI clock and data pins). I'm using SPI. The 8x8 matrix code works (lights up the first panel in the daisy chain), but when I try to change the dimensions (to, e.g. 8x16, to represent two panels), nothing works. Even the first panel doesn't light up.

EDIT: Actually, you made me think to go check the source code (https://github.com/adafruit/Adafruit_Do ... Matrix.cpp ), and there is another constructor for tiled matrices that I could try. I'll give that a shot when I get back home. Its' weird though, that that constructor looks an awful lot like the non-SPI constructor.

The tiled matrices constructor:
Code: Select all | TOGGLE FULL SIZE
// Constructor for tiled matrices w/hardware SPI:
Adafruit_DotStarMatrix::Adafruit_DotStarMatrix(uint8_t mW, uint8_t mH,
  uint8_t tX, uint8_t tY, uint8_t matrixType, uint8_t ledType)


The bitbang single-matrix SPI constructor:
Code: Select all | TOGGLE FULL SIZE
// Constructor for single matrix w/bitbang SPI:
Adafruit_DotStarMatrix::Adafruit_DotStarMatrix(int w, int h,
  uint8_t d, uint8_t c, uint8_t matrixType, uint8_t ledType)


Looks like, if I cast those first two arguments to uint_8, it'll switch to the tiled matrix constructor. This seems like bad practice in method signatures, but I don't know enough about C++ to really be sure.

EDIT #2: Nope. Changing constructors to the one for tiled matrices had no effect.

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by adafruit_support_carter on Fri Feb 09, 2018 3:13 pm

EDIT #2: Nope. Changing constructors to the one for tiled matrices had no effect.

Paste your code for this.

adafruit_support_carter
 
Posts: 4036
Joined: Tue Nov 29, 2016 2:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Fri Feb 09, 2018 4:43 pm

adafruit_support_carter wrote:
EDIT #2: Nope. Changing constructors to the one for tiled matrices had no effect.

Paste your code for this.


Code: Select all | TOGGLE FULL SIZE
// Sketch to accompany "Sipping Power With NeoPixels" guide.  Designed for
// Adafruit Circuit Playground but could be adapted to other projects.

#include <SPI.h>
#include <Adafruit_DotStarMatrix.h>

// GLOBAL VARIABLES --------------------------------------------------------

// This bizarre construct isn't Arduino code in the conventional sense.
// It exploits features of GCC's preprocessor to generate a PROGMEM
// table (in flash memory) holding an 8-bit unsigned sine wave (0-255).
const int _SBASE_ = __COUNTER__ + 1; // Index of 1st __COUNTER__ ref below
#define _S1_ (sin((__COUNTER__ - _SBASE_) / 128.0 * M_PI) + 1.0) * 127.5 + 0.5,
#define _S2_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ _S1_ // Expands to 8 items
#define _S3_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ _S2_ // Expands to 64 items
const uint8_t PROGMEM sineTable[] = { _S3_ _S3_ _S3_ _S3_ }; // 256 items

// Similar to above, but for an 8-bit gamma-correction table.
#define _GAMMA_ 2.6
const int _GBASE_ = __COUNTER__ + 1; // Index of 1st __COUNTER__ ref below
#define _G1_ pow((__COUNTER__ - _GBASE_) / 255.0, _GAMMA_) * 255.0 + 0.5,
#define _G2_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ _G1_ // Expands to 8 items
#define _G3_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ _G2_ // Expands to 64 items
const uint8_t PROGMEM gammaTable[] = { _G3_ _G3_ _G3_ _G3_ }; // 256 items

// These are used for 'debouncing' the left & right button inputs,
// for switching between modes.
// boolean  prevStateLeft, prevStateRight;
// uint32_t lastChangeTimeLeft = 0, lastChangeTimeRight = 0;
// #define  DEBOUNCE_MS 15 // Button debounce time, in milliseconds

// These are used in estimating (very approximately) the current draw of
// the board and NeoPixels.  BASECURRENT is the MINIMUM current (in mA)
// used by the entire system (microcontroller board plus NeoPixels) --
// keep in mind that even when "off," NeoPixels use a tiny amount of
// current (a bit under 1 milliamp each).  LEDCURRENT is the maximum
// additional current PER PRIMARY COLOR of ONE NeoPixel -- total current
// for an RGB NeoPixel could be up to 3X this.  The '3535' NeoPixels on
// Circuit Playground are smaller and use less current than the more
// common '5050' type used in NeoPixel strips and shapes.
#define BASECURRENT 10
#define LEDCURRENT  13.3 // Try using 18 for '5050' NeoPixels
#define BRIGHTNESS  32
uint8_t  frame = 0;    // Frame count, results displayed every 256 frames
uint32_t sum   = 0;    // Cumulative current, for calculating average
uint8_t *pixelPtr;     // -> NeoPixel color data

void mode_off();
void mode_white_max();
void mode_white_half_duty();
void mode_white_half_perceptual();
void mode_primaries();
void mode_colorwheel();
void mode_colorwheel_gamma();
void mode_half();
void mode_sparkle();
void mode_marquee();
void mode_sine();
void mode_sine_gamma();
void mode_sine_half_gamma();

// This array lists each of the display/animation drawing functions
// (which appear later in this code) in the order they're selected with
// the right button.  Some functions appear repeatedly...for example,
// we return to "mode_off" at several points in the sequence.
void (*renderFunc[])(void) {
  mode_off, // Starts here, with LEDs off
  mode_white_max, mode_white_half_duty , mode_white_half_perceptual, mode_off,
  mode_primaries, mode_colorwheel, mode_colorwheel_gamma,
  mode_half, mode_sparkle,
  mode_marquee, mode_sine, mode_sine_gamma, mode_sine_half_gamma
};
const int N_MODES = (sizeof(renderFunc) / sizeof(renderFunc[0]));
uint8_t mode = 0; // Index of current mode in table
long int lastChangeTime;
#define MODE_CHANGE_TIME_MS 5000    //milliseconds between mode changes.

Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 uint8_t(8), uint8_t(8), uint8_t(1), uint8_t(2),
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);


// SETUP FUNCTION -- RUNS ONCE AT PROGRAM START ----------------------------

void setup() {
  matrix.begin();
  matrix.setBrightness(BRIGHTNESS); // NeoPixels at full brightness
  pixelPtr = matrix.getPixels();

  Serial.begin(19200);

  // prevStateLeft  = matrix.leftButton(); // Initial button states
  // prevStateRight = matrix.rightButton();
}

// LOOP FUNCTION -- RUNS OVER AND OVER FOREVER -----------------------------

void loop() {

  // Read and debounce left/right buttons
  uint32_t t = millis();
  // if((t - lastChangeTimeLeft) >= DEBOUNCE_MS) {
  //   boolean b = matrix.leftButton();
  //   if(b != prevStateLeft) {             // Left button state changed?
  //     prevStateLeft      = b;
  //     lastChangeTimeLeft = t;
  //     if(b) {                            // Left button pressed?
  //       if(mode) mode--;                 // Go to prior mode
  //       else     mode = N_MODES - 1;     // or "wrap around" to last mode
  //       frame = sum = 0;                 // Reset power calculation
  //     }
  //   }
  // }
  // if((t - lastChangeTimeRight) >= DEBOUNCE_MS) {
  //   boolean b = matrix.rightButton();
  //   if(b != prevStateRight) {            // Right button state changed?
  //     prevStateRight      = b;
  //     lastChangeTimeRight = t;
  //     if(b) {                            // Right button pressed?
  //       if(mode < (N_MODES-1)) mode++;   // Advance to next mode
  //       else                   mode = 0; // or "wrap around" to start
  //       frame = sum = 0;                 // Reset power calc
  //     }
  //   }
  // }

  //for now, just change modes every ten seconds or something.
  if((t-lastChangeTime) >= MODE_CHANGE_TIME_MS){
    mode = (mode+1) % N_MODES;
    lastChangeTime=t;
  }

  (*renderFunc[mode])();          // Render one frame in current mode
  matrix.show(); // and update the NeoPixels to show it

  // Accumulate total brightness value for all NeoPixels (assumes RGB).
  for(uint8_t i=0; i<matrix.numPixels() * 3; i++) {
    sum += pixelPtr[i];
  }
  if(!++frame) { // Every 256th frame, estimate & print current
    Serial.print(BASECURRENT + (sum * (LEDCURRENT * BRIGHTNESS / 256) + 32640) / 65280);
    Serial.println(" mA");
    sum = 0; // Reset pixel accumulator
  }
}

// RENDERING FUNCTIONS FOR EACH DISPLAY/ANIMATION MODE ---------------------

// All NeoPixels off
void mode_off() {
  matrix.clear();
}

// All NeoPixels on at max: white (R+G+B) at 100% duty cycle
void mode_white_max() {
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, 0xFFFFFF);
  }
}

// All NeoPixels on at 50% duty cycle white.  Numerically speaking,
// this is half power, but perceptually it appears brighter than 50%.
void mode_white_half_duty() {
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, 0x7F7F7F);
  }
}

// All NeoPixels on at 50% perceptial brightness, using gamma table lookup.
// Though it visually appears to be about half brightness, numerically the
// duty cycle is much less, a bit under 20% -- meaning "half brightness"
// can actually be using 1/5 the power!
void mode_white_half_perceptual() {
  uint32_t c = pgm_read_byte(&gammaTable[127]) * 0x010101;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    matrix.setPixelColor(i, c);
  }
}

// Cycle through primary colors (red, green, blue), full brightness.
// Because only a single primary color within each NeoPixel is turned on
// at any given time, this uses 1/3 the power of the "white max" mode.
void mode_primaries() {
  uint32_t c;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    // This animation (and many of the rest) pretend spatially that there's
    // 12 equally-spaced NeoPixels, though in reality there's only 10 with
    // gaps at the USB and battery connectors.
    uint8_t j = i + (i > 4);     // Mind the gap
    j = ((millis() / 100) + j) % 12;
    if(j < 4)      c = 0xFF0000; // Bed
    else if(j < 8) c = 0x00FF00; // Green
    else           c = 0x0000FF; // Blue
    matrix.setPixelColor(i, c);
  }
}

// HSV (hue-saturation-value) to RGB function used for the next two modes.
uint32_t hsv2rgb(int32_t h, uint8_t s, uint8_t v, boolean gc=false) {
  uint8_t n, r, g, b;

  // Hue circle = 0 to 1530 (NOT 1536!)
  h %= 1530;           // -1529 to +1529
  if(h < 0) h += 1530; //     0 to +1529
  n  = h % 255;        // Angle within sextant; 0 to 254 (NOT 255!)
  switch(h / 255) {    // Sextant number; 0 to 5
   case 0 : r = 255    ; g =   n    ; b =   0    ; break; // R to Y
   case 1 : r = 254 - n; g = 255    ; b =   0    ; break; // Y to G
   case 2 : r =   0    ; g = 255    ; b =   n    ; break; // G to C
   case 3 : r =   0    ; g = 254 - n; b = 255    ; break; // C to B
   case 4 : r =   n    ; g =   0    ; b = 255    ; break; // B to M
   default: r = 255    ; g =   0    ; b = 254 - n; break; // M to R
  }

  uint32_t v1 =   1 + v; // 1 to 256; allows >>8 instead of /255
  uint16_t s1 =   1 + s; // 1 to 256; same reason
  uint8_t  s2 = 255 - s; // 255 to 0

  r = ((((r * s1) >> 8) + s2) * v1) >> 8;
  g = ((((g * s1) >> 8) + s2) * v1) >> 8;
  b = ((((b * s1) >> 8) + s2) * v1) >> 8;
  if(gc) { // Gamma correct?
    r = pgm_read_byte(&gammaTable[r]);
    g = pgm_read_byte(&gammaTable[g]);
    b = pgm_read_byte(&gammaTable[b]);
  }
  return ((uint32_t)r << 16) | ((uint16_t)g << 8) | b;
}

// Rotating color wheel, using 'raw' RGB values (no gamma correction).
// Average current use is about 1/2 of the max-all-white case.
void mode_colorwheel() {
  uint32_t t = millis();
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    matrix.setPixelColor(i,
      hsv2rgb(t + j * 1530 / 12, 255, 255, false));
  }
}

// Color wheel using gamma-corrected values.  Current use is slightly less
// than the 'raw' case, but not tremendously so, as only 1/3 of pixels at
// any time are in transition cases (else 100% on or off).
void mode_colorwheel_gamma() {
  uint32_t t = millis();
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    matrix.setPixelColor(i,
      hsv2rgb(t + j * 1530 / 12, 255, 255, true));
  }
}

// Cycle with half the pixels on, half off at any given time.
// Simple idea.  Half the pixels means half the power use.
void mode_half() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = t + i * 256 / matrix.numPixels();
    j = (j >> 7) * 255;
    matrix.setPixelColor(i, j * 0x010000);
  }
}

// Blue sparkles.  Randomly turns on ONE pixel at a time.  This demonstrates
// minimal power use while still doing something "catchy."  And because it's
// a primary color, power use is even minimal-er (see 'primaries' above).
void mode_sparkle() {
  static uint8_t randomPixel = 0;
  if(!(frame & 0x7F)) {              // Every 128 frames...
    matrix.clear(); // Clear pixels
    uint8_t r;
    do {
      r = random(matrix.numPixels());                // Pick a new random pixel
    } while(r == randomPixel);       // but not the same as last time
    uint32_t c = random(0xFFFFFF);
    randomPixel = r;                 // Save new random pixel index
    matrix.setPixelColor(randomPixel, c);
  }
}

// Simple on-or-off "marquee" animation w/ about 50% of pixels lit at once.
// Not much different than the 'half' animation, but provides a conceptual
// transition into the examples that follow.
void mode_marquee() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = (t + j * 256 / 12) & 0xFF;
    k = ((k >> 6) & 1) * 255;
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Sine wave marquee, no gamma correction.  Avg. overall duty cycle is 50%,
// and combined with being a primary color, uses about 1/6 the max current.
void mode_sine() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Sine wave with gamma correction.  Because nearly all the pixels have
// "in-between" values (not 100% on or off), there's considerable power
// savings to gamma correction, in addition to looking more "correct."
void mode_sine_gamma() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]);
    k = pgm_read_byte(&gammaTable[k]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}

// Perceptually half-brightness gamma-corrected sine wave.  Sometimes you
// don't need things going to peak brightness all the time.  Combined with
// gamma and primary color use, it's super effective!
void mode_sine_half_gamma() {
  uint32_t t = millis() / 4;
  for(uint8_t i=0; i<matrix.numPixels(); i++) {
    uint8_t j = i + (i > 4);
    uint8_t k = pgm_read_byte(&sineTable[(t + j * 512 / 12) & 0xFF]) / 2;
    k = pgm_read_byte(&gammaTable[k]);
    matrix.setPixelColor(i, k * 0x000100L);
  }
}


roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by adafruit_support_carter on Mon Feb 12, 2018 11:59 am

Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 uint8_t(8), uint8_t(8), uint8_t(1), uint8_t(2),
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);


I think you are missing some flags in the last argument. See the example of using the tiled constructor here:
https://github.com/adafruit/Adafruit_Do ... st.pde#L58

adafruit_support_carter
 
Posts: 4036
Joined: Tue Nov 29, 2016 2:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Mon Feb 12, 2018 3:48 pm

I think you are missing some flags in the last argument. See the example of using the tiled constructor here:
https://github.com/adafruit/Adafruit_Do ... st.pde#L58


d'Oh! I knew I missed something obvious. I'll give that a try. Thanks so much!

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Tue Feb 13, 2018 2:54 pm

I think you are missing some flags in the last argument. See the example of using the tiled constructor here:
https://github.com/adafruit/Adafruit_Do ... st.pde#L58


d'Oh! I knew I missed something obvious. I'll give that a try. Thanks so much!


Doesn't seem to have any effect. One panel = works fine. More than one panel = Nothing at all.

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by adafruit_support_carter on Tue Feb 13, 2018 3:10 pm

Post the constructor you're trying now. Also, post a photo showing how you have the displays daisychained.

adafruit_support_carter
 
Posts: 4036
Joined: Tue Nov 29, 2016 2:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Tue Feb 13, 2018 5:51 pm

adafruit_support_carter wrote:Post the constructor you're trying now. Also, post a photo showing how you have the displays daisychained.


Here's the constructor now:
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 uint8_t(8), uint8_t(8), 2, 1,
 DS_TILE_TOP   + DS_TILE_LEFT   + DS_TILE_ROWS   + DS_TILE_PROGRESSIVE +
 DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);


And a photo of the daisy chain (six panels, but I'm trying to get the first two working, then work up to six). Ignore the incorrect wire colors for VCC / GND. I was tired, but they're connected correctly. I also accidentally pulled the VCC output pad on panel #2, which might cause problems further down the chain, but shouldn't impact tile #2 (I think?)
Image

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by Arudinne on Tue Feb 13, 2018 6:57 pm

Those power wires are quite thin for the amount of current those panels can take. You might be pulling more than they can handle.

Arudinne
 
Posts: 281
Joined: Sun Mar 19, 2017 9:36 pm

Re: Can't Daisychain DotStar matrix?

by adafruit_support_carter on Tue Feb 13, 2018 7:40 pm

How are you connecting the wires to that control board?

One panel = works fine. More than one panel = Nothing at all.

For the one panel, are you using the same code and just changing the constructor? If not, post the working one panel code.

adafruit_support_carter
 
Posts: 4036
Joined: Tue Nov 29, 2016 2:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Tue Feb 13, 2018 8:19 pm

adafruit_support_carter wrote:How are you connecting the wires to that control board?

One panel = works fine. More than one panel = Nothing at all.

For the one panel, are you using the same code and just changing the constructor? If not, post the working one panel code.


The control board is a DFRobot Beetle. Wires are connected to the SPI clock (blue wire) and data (yellow wire) pins (underneath the board). You can sort of see it on the left-hand side of the image above. Control board and all panels are on a common, regulated VCC / GND supplying 5V/15A with ripple rejection caps.

For the one panel, the working code uses the "non-tiled" constructor, from the top of this thread, with the matrix size set to 8 by 8. That is:
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
 8, 8,
 DS_MATRIX_TOP     + DS_MATRIX_LEFT +
 DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
 DOTSTAR_GRB);


EDIT: I should aso make clear that when I say "Nothing at all", in reality, some of the non-initalized matrices have random LEDs lighting up on startup (and staying lit) with random colors. Different every reboot. I assume this is because these panels have not been initialized at all, but figured it's worth mentioning.

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Re: Can't Daisychain DotStar matrix?

by roach374 on Tue Feb 13, 2018 8:52 pm

EUREKA! I may have a clue here.

When I comment out the current calculation code in the loop() method. I can get up to 3 panels working correctly.

...But I can't get a fourth to work. (although it does light up random LEDs when I only initialize three matrices). I've cranked the brightness all the way down to 1, to make sure it's not related to actual current draw / power problems, and the wiring seems fine...

So this works (as a constructor):
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
(uint8_t)8, (uint8_t)8, 3, 1,
DS_TILE_TOP   + DS_TILE_LEFT   + DS_TILE_ROWS      + DS_TILE_PROGRESSIVE +
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
DOTSTAR_GRB);


And this doesn't (nothing lights up at all):
Code: Select all | TOGGLE FULL SIZE
Adafruit_DotStarMatrix matrix = Adafruit_DotStarMatrix(
(uint8_t)8, (uint8_t)8, 4, 1,
DS_TILE_TOP   + DS_TILE_LEFT   + DS_TILE_ROWS      + DS_TILE_PROGRESSIVE +
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_COLUMNS + DS_MATRIX_PROGRESSIVE,
DOTSTAR_GRB);

roach374
 
Posts: 24
Joined: Thu Jan 25, 2018 11:45 pm

Please be positive and constructive with your questions and comments.