Jump to content
  • Announcements

    • alpenwasser

      Please Use CODE Tags   31 Jan 2016

      Welcome to the Programming and Software Design Section,

      When asking for help with programming issues, please use the code tags to enclose your code, it makes things much more easily readable for the people trying to help you, thus improving your chances of actually getting help.
        To add code tags, click the <> button on the editor toolbar, then enter your code in the code editor that appears. If you are on a mobile device, or prefer to use BBCode, you can use [code] // Your code here // It will be syntax highlighted, though not necessarily corectly. [/code] (but the code editor is more consistent and less buggy).
Pangea2017

improving Ambilight/ performance measurement

Recommended Posts

Posted · Original PosterOP

The problem of the "stock" Ambilight with Prismatik is the FPS and inputlag which result in problems with fast cuts in movies or games. The first and most basic idea is build a average to make the transition smother.

Spoiler

  for (i = 0; i <NUM_LEDS; i++) {
    //Build sum
    byte sumr = leds[i].r;
    byte sumg = leds[i].g;
    byte sumb = leds[i].b;
    for (int n = 0; n < AVERAGE_DEPTH; n++) {
      sumr = sumr + ColorHistory[0][i][n];
      sumg = sumg + ColorHistory[1][i][n];
      sumb = sumb + ColorHistory[2][i][n];     
    }
    //Overwrite Array Values
    ColorHistory[0][i][pos] = leds[i].r;
    ColorHistory[1][i][pos] = leds[i].g;
    ColorHistory[2][i][pos] = leds[i].b;  
    //Build average and write values
    leds[i].r = (byte) sumr / (AVERAGE_DEPTH + 1);
    leds[i].g = (byte) sumg / (AVERAGE_DEPTH + 1);
    leds[i].b = (byte) sumb / (AVERAGE_DEPTH + 1) * 0.8;
  }

 

This lead to wrong colors and every few frams flicker and ruined the experience. This effect get stronger when the average is build over more frames. Because the ATmega328p is not the fastet i took a look at the loigic analyzer.

Locking at the histogramm (0 bar is cut off, real value is 5276) there is no value larger 32 which is the max expected value (255/8). This mean that the code is working. The graph is based on a white bar moving from the right to left on a black background with a depth of 8 frames for the average to build.

SHHEswv.png

Looking at the other video (firework) with the depth of 2 and 8 result in general the distribution is unexpected.

JFZLzWU.pngAzj2jhH.png

Spoiler

 

sorry for the bad diagrams, Origin pro is at the moment not installed

IIRgZQO.pngYiC9mke.png

 

r6eZGRs.pngzoCkHVx.png

After verifying that the code work there is more in the logic analyzer. For some reason the clock is not stable (don't know how bad this is) and a very low amount of data is not correct.

8Ea67wY.png

When looking at the startup (255,0,0)(0,255,0)(0,0,255) the output is not correct. Instated of (0,255,0) the wrong (1,254,0) is send. The library is fastLED (WS2801).

Spoiler

rDfH8cW.png

The clock frequency should be 1 MHz.

At least there is no frame dropped at the Arduino site and processing does not take to long.

6pTx7WG.png

The last thing the data is showing the input lag which is added (50 WS2801). Keep in mind that measurement is the SPI output and not with a phototransistor attached to the LED.

PC to Arduino (baud: 115200): 13.25 ms

building the average (depth 8): 1,48  ms 

building the average (depth 2): 0,09 ms

transmitting over SPI (1 MHz): 1,26 ms

 

total inputlag (sum): 16 ms

 

the FPS is around 30 with drops to 17 which is presumably based on the dynamic frame rate output of prismatik.

Spoiler

8j0b9AO.png

 

How can the experience be improved?

  • faster Microcontroller (Teensy32 or STM32)
  • doing the calculation during the input (input is buffered) is not possible on slow chips
  • trying to do interpolation to achieve smother transitions (calculating frames like it is done on TV)
  • replacing serial with USB or trying to push the baud higher (will result in more transmission errors)
  • optimizing the PC software?
  • trying to calibrate the colors

 

After this try have failed what is the next or did someone have already a solution?

The raw data is provided in the zip file.

Adalight Debug.zip

Link to post
Share on other sites

I can't say for sure but I think your program is incorrect.

21 hours ago, Pangea2017 said:

byte sumr = leds[i].r;
byte sumg = leds[i].g;
byte sumb = leds[i].b;

I assume sizeof(byte) == 1. Which means you can not use it to accumulate the sum. Byte is simply too small to hold anything larger than 255. You need to use something larger like short or int to avoid overflow. Of course this will decrease your applications performance because now your mcu will have to deal with larger integer types. One solution to avoid larger integer types would be to calculate average on the fly :

byte average_255 ( byte const a, byte const b ) {
    return ((a ^ b) >> 1) + (a & b);
}

sumr = average_255(sumr,ColorHistory[0][i][n])
sumg = average_255(sumg,ColorHistory[1][i][n])
sumb = average_255(sumb,ColorHistory[2][i][n])

Function average_255 will produce an average of two numbers without using larger intermediate integer types.

The second possible problem is your array access and alignment. You might get an increase of performance if you pack your RGB values in to a single int :

union RGBA {
  int32_t rgba;
  struct {
    int8_t r;
    int8_t g;
    int8_t b;
    int8_t a;
  };
};

RGBA rgba;
rgba.rgba = 0x00FF00FF;
/* or */
rgba.r = 0xFF;
rgba.g = 0x00;
rgba.b = 0xFF;
rgba.a = 0xFF;

In which case you can calculate rgb average in one step(assuming rgba alpha channel is 0) :

RGBA average_rgb ( RGBA const a, RGBA const b ) {
	return (((((a.rgba) ^ (b.rgba)) & 0xfffefefe) >> 1) + ((a.rgba) & (b.rgba)))
}

 

22 hours ago, Pangea2017 said:

How can the experience be improved?

Strap a 20mhz clock oscillator on that b***h. And yes, you should consider using usb/uart interface for avr/pc/avr communications.

Link to post
Share on other sites
Posted · Original PosterOP

@krgesu byte was definitly wrong. After changing it to unsigned short it should work (now need 50% more time 2ms, 8 bit avr sucks).

But i am still having these issues where it flicker (without the additional code it does not flicker) and still no idea where it is coming from.

 

Can this maybe a problem of the power delivery? (50 WS2801 LED on a 5V 5A PSU)

 

byte average_255 ( byte const a, byte const b ) {
    return ((a ^ b) >> 1) + (a & b);
}

sumr = average_255(sumr,ColorHistory[0][i][n])
sumg = average_255(sumg,ColorHistory[1][i][n])
sumb = average_255(sumb,ColorHistory[2][i][n])

average_255 is fine and this would work for depth of two but when going larger this is in a loop. The function you provided would be:

rlvaQkD.png

int8_t a; is signed (-127, 127), uint8_t (0,255)

Which is a efficient way of weighting the newer values higher then older. The problem with this is that it make it relay dark (can be fixed) and still the delay. It still flicker. 

 

If i would understand where the flicker comes from or why doing this is casing it, i would rewrite the code with a round-off error of max. 8, only byte and a way less array read.

 

 

 

Link to post
Share on other sites
4 hours ago, Pangea2017 said:

byte was definitly wrong. After changing it to unsigned short it should work

Well that does not make much sense because now your ColorHistory array is twice as large(I assume). You only need to use larger types for your math part of the code :

short sumr = leds[i].r;
short sumg = leds[i].g;
short sumb = leds[i].b;
4 hours ago, Pangea2017 said:

Which is a efficient way of weighting the newer values higher then older. The problem with this is that it make it relay dark (can be fixed) and still the delay. It still flicker.

Sorry did not thought this trough.

4 hours ago, Pangea2017 said:

If i would understand where the flicker comes from or why doing this is casing it

What do you mean "flicker"? I assume you are using analog write, yes?

Link to post
Share on other sites
Posted · Original PosterOP
8 hours ago, krgesu said:

Well that does not make much sense because now your ColorHistory array is twice as large(I assume). You only need to use larger types for your math part of the code :


short sumr = leds[i].r;
short sumg = leds[i].g;
short sumb = leds[i].b;

Sorry did not thought this trough.

What do you mean "flicker"? I assume you are using analog write, yes?

Have only changed these lines, array is still byte. Short for the array would blow up the tiny ram (8kB).

 

Can upload tomorrow a video. Data is incoming over USB and is converted to Serial (normal Arduino UNO) and is send to the LED over SPI (going through a breadboard and cable extension).

Link to post
Share on other sites

By the looks of it you are driving your led's directly by the pins of the mcu? Or something more elaborate like mosfet transistors? Also are you are using pwm to drive R,G and B brightness to achieve color? If yes do you use code to do it or dedicated pwm?

Link to post
Share on other sites
Posted · Original PosterOP
50 minutes ago, krgesu said:

By the looks of it you are driving your led's directly by the pins of the mcu? Or something more elaborate like mosfet transistors? Also are you are using pwm to drive R,G and B brightness to achieve color? If yes do you use code to do it or dedicated pwm?

they are addressable led, you give them the digital data over SPI and the LED itself have a chip which convert it to the PWM signal

the power is coming from a dedicated PSU which have a common ground with the mcu and give the power direct to the LEDs. No caps are used for stabilisation of the power rail. Without the changes (averaging) it works without a problem.

Link to post
Share on other sites

To be absolutely sure you could split your code which is presumably too slow to calculate average and drive the led's in to two arduino mcu's. One would do the color calculations and the other would do led strip driving. If your led strip is still flickering this would indicate a bug in your color calculation mcu. If not this would be a clear evidence that your mcu or the communications side of thing is too slow for this particular job.

Link to post
Share on other sites
On 1/19/2018 at 8:42 PM, Pangea2017 said:

 No caps are used for stabilisation of the power rail.

None at all? There should be a capacitor near each addressable LED, 100nF typical. Without these, the PWM switching transients can cause unreliable operation of the controller chip inside the leds.

Link to post
Share on other sites
Posted · Original PosterOP
36 minutes ago, Unimportant said:

None at all? There should be a capacitor near each addressable LED, 100nF typical. Without these, the PWM switching transients can cause unreliable operation of the controller chip inside the leds.

They have them and some resistance next to each LED. But i did not have added a larger capacitor which is common practic for the WS2812B.

Link to post
Share on other sites
Posted · Original PosterOP
On 19.1.2018 at 10:09 PM, krgesu said:

To be absolutely sure you could split your code which is presumably too slow to calculate average and drive the led's in to two arduino mcu's. One would do the color calculations and the other would do led strip driving. If your led strip is still flickering this would indicate a bug in your color calculation mcu. If not this would be a clear evidence that your mcu or the communications side of thing is too slow for this particular job.

I don't think it is a performance issue. When looking at the IO there is over 30 ms between the last bit is send to the LED and the next serial input is coming in.

Given that it is running fine without this change the librarys and pc software should be not the problem.

A bug in the color calculation would explain it. But were is it?

Link to post
Share on other sites
Posted · Original PosterOP
//Version 0.9.1.7
//Date 2018-01-15
//#define FASTLED_FORCE_SOFTWARE_SPI
#include "FastLED.h"
//#include "SPI.h"  //for test
 
//define strip
#define NUM_LEDS 50
#define AVERAGE_DEPTH 3 //7 possible
#define COLOR_ORDER BGR 

#define serialRate 115200
#define DATA_PIN 11
#define CLOCK_PIN 13

//Define magic wor
uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i; 
// Define the array of leds
CRGB leds[NUM_LEDS];
// Define the array of History [Color] [LED] [History]
byte ColorHistory[3][NUM_LEDS][AVERAGE_DEPTH];
//Position of the overwrite in the Array
byte pos;

//simulate a overflow at given number
int count (byte number) {
  number++;
  if (number  >  AVERAGE_DEPTH) {
    number = 0;
  }
  return number;
}
 
void setup() {
      //SPI.setClockDivider(SPI_CLOCK_DIV2);   //slowing down or fastening SPI speed     
      FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
      //Array for average (initilisation)
      for (int i = 0; i < 3; i++) {
        for (int j = 0; j < NUM_LEDS; j++) {
          for (int n = 0; n < AVERAGE_DEPTH; n++) {
            ColorHistory[i][j][n] = 0;     
          }
        }
      }   
      //startup signal
      LEDS.showColor(CRGB(255, 0, 0));
      delay(200);
      LEDS.showColor(CRGB(0, 255, 0));
      delay(200);
      LEDS.showColor(CRGB(0, 0, 255));
      delay(200);
      LEDS.showColor(CRGB(0, 0, 0));
       
      Serial.begin(serialRate);
      Serial.print("Ada\n"); //magic word
}

byte average_255 ( byte const a, byte const b ) {
    return ((a ^ b) >> 1) + (a & b);
}
 
void loop() {
  for(i = 0; i < sizeof prefix; ++i) {
    waitLoop: while (!Serial.available()) ;;
    if(prefix[i] == Serial.read()) continue;
    i = 0;
    goto waitLoop;
  }
  while (!Serial.available()) ;;
  hi=Serial.read();
  while (!Serial.available()) ;;
  lo=Serial.read();
  while (!Serial.available()) ;;
  chk=Serial.read(); 
  // if checksum does not match go back to wait
  if (chk != (hi ^ lo ^ 0x55))
  {
    i=0;
    goto waitLoop;
  }
 
  memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
  for (uint8_t i = 0; i < NUM_LEDS; i++) {
    byte r, g, b;    
    while(!Serial.available());
    r = Serial.read();
    while(!Serial.available());
    g = Serial.read();
    while(!Serial.available());
    b = Serial.read();
    leds[i].r = r;
    leds[i].g = g;
    leds[i].b = b;
  }
  //build the average
  for (i = 0; i <NUM_LEDS; i++) {
    //Build sum
    unsigned short sumr = leds[i].r;
    unsigned short sumg = leds[i].g;
    unsigned short sumb = leds[i].b;
    for (int n = 0; n < AVERAGE_DEPTH; n++) {
      sumr = average_255(sumr,ColorHistory[0][i][n]);
      sumg = average_255(sumg,ColorHistory[1][i][n]);
      sumb = average_255(sumb,ColorHistory[2][i][n]);
      /*sumr = sumr + ColorHistory[0][i][n];
      sumg = sumg + ColorHistory[1][i][n];
      sumb = sumb + ColorHistory[2][i][n];  */   
    }
    //Overwrite Array Values
    ColorHistory[0][i][pos] = leds[i].r;
    ColorHistory[1][i][pos] = leds[i].g;
    ColorHistory[2][i][pos] = leds[i].b;  
    //Build average and write values 
    leds[i].r = (byte) sumr / (AVERAGE_DEPTH + 1) * 8;
    leds[i].g = (byte) sumg / (AVERAGE_DEPTH + 1) * 8;
    leds[i].b = (byte) sumb / (AVERAGE_DEPTH + 1) * 0.8 *8;
  }
  //increase Position by one
  pos = count(pos);
  // shows new values
  FastLED.show(); 
}

@krgesu

Link to post
Share on other sites
53 minutes ago, Pangea2017 said:

memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));

Instead of clearing array to 0 set all rgb values to 255 and try to run it.

Link to post
Share on other sites
Posted · Original PosterOP
48 minutes ago, krgesu said:

Instead of clearing array to 0 set all rgb values to 255 and try to run it.

solves the problem but i don't understand why

This line only should change things if the serial transmission does not work properly. In this case i would expect now to see still this flickering but it is runing fine without problem and why did the average have not worked before for those frames.

Link to post
Share on other sites

I don't think this solves the problem. I wanted to see if your algorithm updates every led. And this test shows that you might skip some of the led's. So when it's time to "show" them these un-updated led's have no color because you initialized them to 0 using memset.

On 1/26/2018 at 10:15 AM, Pangea2017 said:

void loop() {
   for(i = 0; i < sizeof prefix; ++i) {
   ...
   }
}

 

What is the type of variable i? You have more of these in your code.

 

Link to post
Share on other sites
Posted · Original PosterOP
6 hours ago, krgesu said:

I don't think this solves the problem. I wanted to see if your algorithm updates every led. And this test shows that you might skip some of the led's. So when it's time to "show" them these un-updated led's have no color because you initialized them to 0 using memset.

What is the type of variable i? You have more of these in your code.

Problem is still there but not flickering.

This is the part i did not touched. The i is global. I know the existing code base i use is at some points bad. The construct with goto waitloop is nothing you should consider to do.

uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i; 

 

Link to post
Share on other sites
On 1/26/2018 at 10:15 AM, Pangea2017 said:

for(i = 0; i < sizeof prefix; ++i)

i++?

 

Who is sending this information trough serial to arduino? Have you checked if rgb values are sent correctly?

Link to post
Share on other sites
Posted · Original PosterOP
10 hours ago, krgesu said:

i++?

 

Who is sending this information trough serial to arduino? Have you checked if rgb values are sent correctly?

i++ and ++i is equal for for

 

PC(prismatik) with USB->Atmel USB to serial -> Atmel 328p

 

Only a few in a couple of thousands are not correct.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

Buy VPN

×