Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By andrew melvin
#16529
Jason Stapels wrote:
Makuna wrote:I started with a very similar routine and it also had glitches and further, the timing was inconsistent (measured by a Logic Analyzer). But I am running with the Wifi connected and a very active animation.

So I did a bunch of different tests with WiFi and doing solid color updates (rather than tons of fading) and I did notice a problem with the first pixel. So I did a quick makeshift 3V -> 5V level shifter and the problem with the first pixel went away***, even when using WiFi.

*** - Actually, I have an issue with the first pixel when I turn on the unit, but I'm pretty sure that's because my ghetto level shifter default to high. But I'll keep playing with it to see, I just can't imagine why my timing would vary unless the internal oscillator is all over the place.


What were you using as a makeshift level converter?
User avatar
By Jason Stapels
#16568
andrew melvin wrote:What were you using as a makeshift level converter?


Basically this: http://husstechlabs.com/support/tutoria ... l-shifter/

However, after lots of testing and monkeying around in the end it all came down to timing. I rewrote my simple library using the same CCOUNT trick that Makuna used. Now I don't have any issues (that I can find), no problems with the first LED, and I'm not using a level shifter. Here's the latest version:

Code: Select all#include <eagle_soc.h>
#include <c_types.h>

//////////
// BEGIN EspNeoPixel functions.
//

// The number of cycles per nanosecond.
#define NS_TO_CYCLES(n) (n / (1000000000L / F_CPU))

// Store the cycle count to a variable.
#define STORE_CYCLES(r) do { \
  __asm__ __volatile__("rsr %0, CCOUNT \n\t" : "=a" (r)); \
} while (0);

// Delay an arbitrary number of cycles past the specified cycle count.
#define DELAY_CYCLES(_cs, _delay) do { \
  uint32_t _cc; \
  do { \
    STORE_CYCLES(_cc); \
  } while ((_cc - _cs) < _delay); \
} while(0);

// Set pins high for a specified number of nanoseconds.
#define DIGITAL_HIGH_NS(_mask, _ns) do { \
  uint32_t _cs; \
  STORE_CYCLES(_cs); \
  GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, _mask); \
  DELAY_CYCLES(_cs, NS_TO_CYCLES(_ns)); \
} while (0);

// Set pins low for a specified number of nanoseconds.
#define DIGITAL_LOW_NS(_mask, _ns) do { \
  uint32_t _cs; \
  STORE_CYCLES(_cs); \
  GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, _mask); \
  DELAY_CYCLES(_cs, NS_TO_CYCLES(_ns)); \
} while(0);

// Holds the pin mask for EspNeoPixel
uint16_t enpPinMask;

//
// EspNeoPixel start.
//
// This disable interrupts and enables the pin for output.
//
// Call this before a sequence of pin updates with the pin the WS2812's are hooked up to.
// Note that this could be make to accept a pinMask in case you wanted to control multiple
// strips at the same time (albeit with the same colors).
//
// pin - The pin the WS2812's are hooked up to.
//
void enpStart(uint8_t pin) {
  enpPinMask = 1 << pin;

  pinMode(pin, OUTPUT);    // set pin as output
  digitalWrite(pin, LOW);  // set it low
  delay(10);
  noInterrupts();          // disable interrupts
}

//
// EspNeoPixel send byte.
//
// This sends a byte out to the WS2812. It should be called three times per pixel,
// once for green, once for red, and once for blue.
//
// The timing in this function is absolutely critical, more info can be found here:
// http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
//
// val - An unsigned byte encoded with 8 bits of color information.
//
void ICACHE_FLASH_ATTR enpSendByte(uint8_t data) {
  uint8_t b = 8;
  while (b > 0) {   // loop 8 times, once for each bit
    b--;
    if ((data & (1 << b))) {             // check if current bit is high/low
      DIGITAL_HIGH_NS(enpPinMask, 700);  // send WS2812 '1'             
      DIGITAL_LOW_NS(enpPinMask, 600);
    } else {
      DIGITAL_HIGH_NS(enpPinMask, 350);  // send WS2812 '0'
      DIGITAL_LOW_NS(enpPinMask, 800);
    }
  }
}

//
// EspNeoPixel send pixel.
//
// This sends out three bytes (in the correct order) to light a single pixel.
//
// red - unsigned byte of red color information
// grn - unsigned byte of green color information
// blu - unsigned byte of blue color information
//
void enpSendPixel(uint8_t red, uint8_t grn, uint8_t blu) {
  enpSendByte(grn);
  enpSendByte(red);
  enpSendByte(blu);
}

//
// EspNeoPixel stop sending data.
//
// This will re-enable interrupts and wait a small amount of time to enable the pixels.
//
void enpStop() {
  interrupts();
  delayMicroseconds(50);
}

//
// END EspNeoPixel functions.
//////////


Please let me know if you run into an issue for my own curiosity :).
User avatar
By andrew melvin
#16577 Cheers,

I will look into that, and let you know. I've got a lot on at the moment so it might have to wait...

My project has basically evolved.

I had an ESP controlling a strip behind my TV, I managed to get marks's WS2812 code working with the adafruit lib. And it worked, worked well actually. However, I'm currently using a raspberry pi, with rasplex. I have been since the day they released it for the pi2. and their latest version has.... hyperion support enabled.. with a simple tick box. Now hyperion doesn't natively support the WS2812, as it doesn't have the timing line... BUT... connect the WS2812 to an arduino. Load a very simple script, upload a hyperion config file set to /dev/usb01 serial (something like that) and boom.. you have ambilight working immediately. I'm using a nano which has the serial chip on it. Really awesome.

The only downside is that hyperion does not have any 'easy' ways that i can find to control it all using html/mqtt... and thats how i integrate everything into my home automation. every room has a page, with heating, lights... etc.... and this i did have working very nicely with mqtt.... so the next step is to get this working with an ESP, or an arduino with software serial pointed at an ESP with espduino loaded... the aim... have it so i can select... 1) TV i.e. ambilight, 2) visual spectrum using a MSGEQ7, animations with speed control, 3) and color, fade pattern.... etc...

I can't see this all being easy to implement through hyperion from what i can see... but the code to put hyperion from serial to ws2812s using fastLED looks... well pretty simple.
User avatar
By Makuna
#16586
Jason Stapels wrote:
Code: Select all
// Store the cycle count to a variable.
#define STORE_CYCLES(r) do { \
  __asm__ __volatile__("rsr %0, CCOUNT \n\t" : "=a" (r)); \
} while (0);


Please let me know if you run into an issue for my own curiosity :).


Two things...
1) have you tried this while WiFi is active and you are "animating" the strip? This seems to be where things break down for me.

2) In the code I quoted, why the "do while" around the asm?