Close
0%
0%

Cree Dimming Level

Getting discrete dimming level value out of the Zigbee board from a Cree Connected Bulb.

Similar projects worth following

Inspired by this CreeRelays project, I wanted to build something that reads the dimming levels of the Zigbee board in the Cree Connected Bulb. After a few attempts using the strategy there, I found a few problems. First, the PWM output from the Cree board is not entirely linear, so the way CreeRelays maps to dimming level doesn't quite work for all the levels. That could be fixed with a lookup table.

The second problem I couldn't solve with just the Arduino: The timing is so sensitive reading the PWM signal from the Cree board that trying to do anything else with the Arduino, especially any operations requiring interrupts, threw off the readings.

The solution: Use a separate DAC to convert the PWM signal to a fixed voltage, and monitor that on an Arduino analog pin for changes.

Once I had the DAC hooked up, I set the bulb to each of the 100 dim levels, and recorded the data out of the analog pin for about 30 seconds. The analog pin on the Arduino returns a value from 0 to 1023. Each dimming level fluctuated between 2 and 5 different values, with the bulk of it usually being just 2. From the data I collected, I created a count of how many of each value were read for each level. I dropped values that had very few results, and used the resulting data to create the "cutoffs" array in the Arduino sketch. These are the start and end point for each dimming level on the bulb. The raw (grouped) data can be found in data.txt.

When the bulb changes brightness, there's a ramp up or ramp down time, and the intermediate values are output in the PWM signal. Due to this, in the Arduino sketch, I have to wait until the value stabilizes when it is changing before being sure that it's changed to a new dimming level. The number of readings before calling it stable was determined simply through trial and error.

In the attached CreeRead.mp4 video file, you can see output from the Arduino with the proper dimming level when it is changed through a Staples Connect home automation hub.

CreeRead.mp4

Demonstration of the project. The Cree board is connect to a Staples Connect home automation hub, on the right. The Arduino serial terminal is on the left. You can see the output from the Arduino as I change the settings on the bulb.

MPEG-4 Video - 1.55 MB - 01/14/2017 at 03:16

Download

CreeBoardRead.ino

Arduino sketch to read Cree dimmer level.

ino - 3.27 kB - 01/14/2017 at 02:30

Download

data.txt

Raw data for voltage levels read on the Arduino analog pin.

plain - 215.76 kB - 01/12/2017 at 21:33

Download

  • 1
    Step 1

    Wire the Cree Zigbee board to the LTC2644 and Arduino as shown in the schematic or picture. Note that pin 1 on the Cree board is towards the middle of the board, and pin 4 is towards the outer edge.

    Everything is currently powered by the USB to TTL programmer connected to the Arduino, but a 3.3v regulator would work as well. I bring VCC and GND out from Arduino pins 4 and 21 to my breadboard power bus.

    • Zigbee board pin 1: GND
    • Zigbee board pin 2: VCC
    • Zigbee board pin 3: LTC2644 pin 9 (IN_A)
    • Zigbee board pin 4: Arduino digital input 9 (pin 12 on the Arduino Pro Mini)

    The LTC2644 wiring:

    • Pin 1: VCC
    • Pin 2: Arduino analog input A0 (pin 17 on the Arduino Pro Mini.) This is the analog output converted from the PWM signal.
    • Pin 3: Unused
    • Pin 4: IDLSEL to GND. Prevents DAC from powering down if there is no PWM signal for a while.
    • Pin 5: IOVCC to VCC. Voltage level of the I/O input supply.
    • Pin 6: GND
    • Pin 7: VCC to put the chip in normal operation mode instead of a power-down mode.
    • Pin 8: Unused.
    • Pin 9: Zigbee board pin 3. This is the PWM signal from the Cree bulb board.
    • Pin 10: VCC for reference voltage. The DAC scales the analog output with this reference as the maximum voltage.
    • Pin 11: VCC. Tells the DAC to use pin 10 as the reference voltage instead of an internal reference.
    • Pin 12: GND

    Schematic

    Circuit

  • 2
    Step 2

    Flash the Arduino with the following sketch. This is also included as a file attached to the project.

    int last_level = 0;
    bool last_state = false;
    bool stable = false;
    int count = 0;
    
    const int cutoffs[198] = {/* 1*/ 833, 831, /* 2*/ 825, 823, /* 3*/ 817, 816, /* 4*/ 809, 808, /* 5*/ 801, 800,
                              /* 6*/ 793, 791, /* 7*/ 785, 783, /* 8*/ 773, 771, /* 9*/ 769, 767, /*10*/ 757, 755,
                              /*11*/ 753, 751, /*12*/ 741, 739, /*13*/ 733, 731, /*14*/ 725, 723, /*15*/ 717, 716,
                              /*16*/ 709, 708, /*17*/ 697, 695, /*18*/ 693, 691, /*19*/ 681, 680, /*20*/ 677, 675,
                              /*21*/ 665, 664, /*22*/ 661, 659, /*23*/ 649, 648, /*24*/ 641, 640, /*25*/ 633, 632,
                              /*26*/ 625, 624, /*27*/ 617, 616, /*28*/ 605, 604, /*29*/ 601, 600, /*30*/ 589, 588,
                              /*31*/ 585, 584, /*32*/ 573, 572, /*33*/ 569, 568, /*34*/ 557, 556, /*35*/ 549, 548,
                              /*36*/ 541, 540, /*37*/ 533, 532, /*38*/ 525, 524, /*39*/ 513, 512, /*40*/ 509, 508,
                              /*41*/ 496, 496, /*42*/ 493, 492, /*43*/ 480, 479, /*44*/ 477, 472, /*45*/ 464, 463,
                              /*46*/ 456, 455, /*47*/ 448, 447, /*48*/ 440, 439, /*49*/ 432, 431, /*50*/ 420, 419,
                              /*51*/ 416, 415, /*52*/ 404, 403, /*53*/ 400, 399, /*54*/ 388, 387, /*55*/ 380, 379,
                              /*56*/ 372, 371, /*57*/ 364, 363, /*58*/ 356, 355, /*59*/ 348, 347, /*60*/ 340, 339,
                              /*61*/ 332, 331, /*62*/ 324, 322, /*63*/ 312, 310, /*64*/ 308, 307, /*65*/ 296, 295,
                              /*66*/ 287, 287, /*67*/ 280, 279, /*68*/ 271, 271, /*69*/ 263, 263, /*70*/ 255, 255,
                              /*71*/ 247, 246, /*72*/ 239, 238, /*73*/ 231, 230, /*74*/ 223, 222, /*75*/ 215, 210,
                              /*76*/ 204, 202, /*77*/ 196, 194, /*78*/ 188, 186, /*79*/ 179, 178, /*80*/ 171, 170,
                              /*81*/ 163, 162, /*82*/ 155, 154, /*83*/ 147, 146, /*84*/ 139, 138, /*65*/ 131, 130,
                              /*86*/ 119, 118, /*87*/ 115, 114, /*88*/ 103, 102, /*89*/  95,  94, /*90*/  87,  86,
                              /*91*/  79,  78, /*92*/  71,  70, /*93*/  63,  62, /*94*/  55,  54, /*95*/  47,  42,
                              /*96*/  39,  38, /*97*/  27,  26, /*98*/  23,  22, /*99*/  11,  10 };
    
    void setup() {
      Serial.begin(115200);
      pinMode(A0, INPUT);
      pinMode(9, INPUT);
    }
    
    int getlevel(int value) {
      if (value == 0) return 100;
      if (value > 900) { return 0; } 
      for (int i = 0; i < 198; i+= 2) {
        if (value <= cutoffs[i] && value >= cutoffs[i+1]) {
            return (i / 2) + 1;
        }
      }
      return -1;
    }
    
    // the loop function runs over and over again forever
    void loop() {
      int level = 0, dimlevel = 0;
    
      /* read on/off status from Cree board */
      int state = digitalRead(9);
      if (state != last_state) {
        Serial.print("Bulb switched to: ");
        Serial.println(state ? "ON" : "OFF");
        last_state = state;
      }
    
      for (int i = 0; i < 5; i++) {
        level += analogRead(A0);
        delay(5);
      }
      level /= 5;
    
      dimlevel = getlevel(level);
      if (dimlevel == -1) { return; }
      if (dimlevel != last_level) {
        last_level = dimlevel;
        count = 0; 
        stable = false;
      } else { 
        count++;
        if (count > 4 && !stable) {
          Serial.print("Level changed to: ");
          Serial.println(dimlevel);
          stable = true;    
        }
      }
    }

View all instructions

Enjoy this project?

Share

Discussions

Laurent wrote 01/23/2017 at 23:41 point

Awesome project!

I have been battling the Cree dimming function too. I tried measuring the PWM in various digital ways, but found it was too unstable. I ended up with a simple RC low pass filter (RC=100ms, so about 1/10 the PWM frequency) into an Arduino analog pin. That cleaned up the signal a lot. It's not perfect, but usable for my purpose (drive the digital brightness of programmable RGB LEDs) and a bit of Arduino code can help with the remaining jitter/ripple.

How stable is the DAC route with the measured steps? 100% stable?

  Are you sure? yes | no

Alan Penner wrote 01/28/2017 at 19:07 point

I tried the low pass filter, but couldn't make it work well enough. But I didn't realize until later that the ESP8266 has issues reliably using the analog pin. I only found that out after I switched to the DAC and still couldn't make it work, then moved on to the Arudino Pro Mini.

With the DAC, the readings for each dimming level fluctuate between 2 and 5 values depending on the level. With the Arduino sketch, it's rock solid determining the actual level set from 1-99. All the raw data counts can be found in the data.txt file attached. 

I will say that while I found the PWM output not quite linear (hence needing a lookup table instead of just a map or calculation), it could be just the way the values are being set from my controller. I'm using a Staples Connect to set the 1-99 level. I read somewhere that the Cree board actually has 255 levels, so the non-linear issue I'm seeing may just be that the Staples Connect doesn't map 1-99 to 1-254 linearly. With a different controller, it's possible my numbers won't work correctly.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates