Help pls: WS2812B leds.show() stops rx and decoding of 433mhz Manchester msg

Hi, Please could you help me with a (potential) neopixel issue? I am trying to use WS2812 leds (42 on a strip) and am using the adafruit neopixel library. I am also using Manchester encoding to receive a 433mhz rf control signal (4 digit number) and I hope to use that number to select the lighting pattern. Everything works fine until I include the leds.show() line of code. If I // this line out the Manchester encoded rf signal can be received and decoded. With this line of code running, I get no Manchester message decoded. Does this sound like an rf noise from turning on the led strip (I have tried remoting the receiver 20cm from the arduino and both rx and tx have 173mm wire antennae) or does it sound like a timing issue with the neopixel library (perhaps not listening for the Manchester signal long enough to receive it)? Grateful for any help you can offer in solving this.

Sketch and schematic please!

Sorry, I realise I have been a poor poster. I'm not sure how to do a schematic but I'll work on it and get back to this topic. As for the code, I have tried to isolate the issue by using a very simple lighting pattern in the following code. Hope it helps explain what I'm trying to do.

/* Test to try and isolate problems when using 433mhz manchester encoded signal to
control which pattern is sent to WS2812B addressable LEDs*/

#include "Adafruit_NeoPixel.h"
#include "WS2812_Definitions.h"
#include <Manchester.h>

/*
From the manchester example code - I am using 1200 rate.
  Manchester Receiver example
  In this example receiver will receive one 16 bit number per transmittion
  try different speeds using this constants, your maximum possible speed will 
  depend on various factors like transmitter type, distance, microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7
*/

#define RX_PIN 3 //is the data pin for the receiver
#define LED_PIN 13 //is the onboard LED pin
#define powerPin 4 //will supply 5v to the 433mhz receiver

#define PIN 8 //is the data pin for sending data to the WS2812B LED strip
#define LED_COUNT 42 // is the number of LEDs on the strip

uint8_t moo = 1; //this is the number used to flash the onboard led on and off when manchester code has been successfully received and decoded
int indicatorState; //this stores the 4digit number from the decoded manchester code
// Create an instance of the Adafruit_NeoPixel class called "leds".
// That'll be what we refer to from here on...
Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_GRB + NEO_KHZ800);

int i; //for the "for" statement increments

void setup() {
  pinMode(LED_PIN, OUTPUT); //sets the onboard led to an output
  pinMode(powerPin, OUTPUT);  //sets the pin which will supply power to the 433mhz receiver as an output
  digitalWrite(powerPin, HIGH);// turns the power on to the pin which will be the 5v supply to the 433mhx receiver
  man.setupReceive(RX_PIN, MAN_1200);//sets up the manchester decoding
  man.beginReceive(); //start listening for manchester code
  Serial.begin(9600);//so I can read the 4 digit number being received and decoded
  leds.begin();  // Call this to start up the LED strip.
  clearLEDs();   // This function, defined below, turns all LEDs off...
  leds.show();   // ...but the LEDs don't actually update until you call this.
}


void loop() {
  if (man.receiveComplete()) {
    uint16_t m = man.getMessage();//retrieve the decoded value and set m as this value
    man.beginReceive(); //start listening for next message right after you retrieve the message
    moo = ++moo % 2; //alternate moo between 0 and 1
    digitalWrite(LED_PIN, moo); //turn the onboard LED on or off, depending on the value of moo
    indicatorState = m; //set indicatorState to the value of the decoded number
    Serial.println(indicatorState); //so I can check if the 4 digit number has been received and decoded using the serial monitor
  }
  if(indicatorState == 7561) {  //the 4 digit number being sent is 7561 - needs to be complex to avoid cross-talk
    AllRed(); //carry out the AllRed function below
  }
  else {
    clearLEDs(); //turn the LEDs off if indicatorState doesn't equal 7561
  }
  leds.show(); //The problem statement - if this is turned off, I have no problem turning the onboard LED on and off using the 433mhx tx/rx
}

//code to set all the leds on the strip red
void AllRed()
{
  for(i=0; i<LED_COUNT; i++) {
  leds.setPixelColor(i, RED);  // Set the LEDs red 
  }
}
// Sets all LEDs to off, but DOES NOT update the display;
// call leds.show() to actually turn them off after this.
void clearLEDs()
{
  for (int i=0; i<LED_COUNT; i++)
  {
    leds.setPixelColor(i, 0);
  }
}

Just use pencil and paper, keep it neat, scan it or use your phone camera. Also post links to your rf components.

Can't see a problem with your sketch at first reading but I'm not familiar with that Manchester library.

Your theory about the ws2812 leds causing interference is worth investigating. Try 0.1uF and 100uF across the power rail close to the leds.

Paul

Thank you so much. I have had a crack at a schematic, attached. I have ordered the capacitors you mentioned but I tried with a 220uF one I had to no avail.

Does the .show() function stop the arduino listening for or decoding the message?
Thanks, Simon

Hi smerrett79

Building on what PaulRB said and what you have tried, Adafruit recommend a 1,000uF capacitor across the neopixel power connections. Also, a 330 to 470 Ohm resistor between the Arduino data output pin and the input to the first neopixel, at the neopixel end of the connection.

But maybe before that, what happens if you disconnect the neopixels (leaving the code in your program)? If there were a clash between the neopixel library and the Manchester code library, this ought to show up even if no neopixels are attached.

I know that the neopixel library disables interrupts when it sends the data to the neopixels.

Regards

Ray

Good theory, Ray. Manchester library relies on interrupts and neopixel temporarily disables them, causing missed events. I bet same would be true if sketch was expecting to receive data on the Serial port. If so, might explain the issue on this thread.

Looking again at the code, leds.show() is being called on every iteration of loop(), whether or not the state of the LEDs has changed. If there is an "interrupts" issue, this may make the situation worse.

How about calling leds.show() only when the indicator changes.

Declare a couple of extra variables ...

int prevState = 0;
boolean ledsChange = false;

Then change the latter part of loop() to be ...

  if (indicatorState == 7561)
  {  
      if (prevState != 7561)
      {
            AllRed(); 
            prevState = indicatorState;
            ledsChanged = true;
      }
  }
  else if (prevState == 7561) // and indicatorState != 7561
  {
        clearLEDs();
        prevState = indicatorState;
        ledsChanged = true;
  }
  if (ledsChanged)
  {
      leds.show();
      ledsChanged = false;
  }

Guys, thanks for your thoughts.

First, I tried unplugging the led strip and using the pin13 LED to determine whether the manchester code had been received and decoded. The problem persisted with this setup, indicating, as Ray says, that a code clash is more likely than electromagnetic interference.

Ray, your idea of reducing the updates .show() to only those instances where a state has changed is great and I can make use of it in my main program. However, the code above is a simplified one to try and sort the problem out. In my main program I have a default setting (unless a 4 digit manchester encoded message changes the indicatorState) where a single LED is lit for 50ms before turning off and the adjacent one turning on, to give the effect of a light running along the strip. This 50ms interval can go to 70ms but anything longer undermines the smoothness and looks juddery. It would be great if I can continue to use this 50ms update rate while still listening for the manchester messages. I have upped the transmission rate to 2400 on the manchester setup to try and fit a message into a smaller time window but I'm not convinced that it has made a huge difference (no effect). I'm using atTiny85 without an external oscillator to generate the tx, so can't go higher with tx/rx rate.

So, what next for this investigation? You mentioned disabling interrupts and I read (but didn't fully understand) the linked thread about serial problems. What might be a fruitful next step? Thanks, Simon

Simon

Understand about needing to update the LEDs every 50ms.

Have you tried that in your test code? Call show() based on a "blink without delay" style timer every 50ms. It might show that there is enough "spare time" between LED updates to receive the command via RF (assuming the ATtiny repeatedly sends the command).

Regards

Ray

I have tried a "without delay" version every 50ms and have managed to get intermittent manchester messages through to my Pro Mini. My atTiny85 is sending on repeat with a 20ms delay between transmissions (nervous that back-to-back tx might get confusing for rx but I am clutching at straws and have no evidence that the delay between tx is useful). The range (with 173mm 1/4 wavelength wire antennae) is about 1m (I need 3m preferably), is hugely dependent on antennae orientation and the reliability is nowhere near good enough but it's progress nonetheless! Thanks Ray.

I will try tx without the 20ms delay next. Does anyone have any thoughts on whether RC_Switch or VirtualWire libraries might be better at this application (i.e. not rely on interrupts or take less time to receive a message)? Can we do anything about the interrupt disabling in Neopixel library? Thanks, Simon

Can we do anything about the interrupt disabling in Neopixel library?

Unlikely, I think. The comments in the library stress the criticality of the timing of that part of the code, which is written in inline assembly language. But it might be worth your while posting a question on the Adafruit website.

Ray, good comment. I am way out of my depth wrt libraries and interrupts but this post gives me hope that there might be a way of using the WS2812B strip with a less fussy program than Neopixel library results in: NeoPixels Revealed: How to (not need to) generate precisely timed signals | josh.com

If you have time to scan read it, I'd be very grateful to hear if it looks worthy of pursuit. Simon

Will do! I'm working on a large neopixel project at the moment. Fortunately, all the timing is driven from the Arduino which manages the neopixels, so I can interlace the show()s with polling the other devices, etc. But if there is another way, that would be a good insurance policy for me.