WS2812 LED control on atmega328p

Go To Last Post
49 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have recently been trying to turn on my rgb led strip all at once however i have only found out how to address them one at a time. Are these leds able to be addressed as one? I havee tried several libraries like fastLED and various arduino librraries which I would convert over but nothing seems to work. Any ideas?

 

Heres my code:

 

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"

struct cRGB led[24];

int main(void)
{
  DDRB = 0b00000001;
  uint8_t pixelCount = 24;
  while (1)
  {
    uint8_t i = 0;
    for (i = pixelCount; i > 1; i--){
      led[i - 1] = led[i - 2];
    }
    led[0].r = 0;
    led[0].g = 0;
    led[0].b = 255; // color code
    ws2812_setleds(led, pixelCount);
  }
}
 

Attachment(s): 

This topic has a solution.
Last Edited: Fri. Jan 18, 2019 - 03:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What does the datasheet say?  https://cdn-shop.adafruit.com/da...

 

Jim

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It does not state much. In order for me to turn on a strand of 100 it takes a solid 5 seconds. But there is not any delays other than 1 10ms delay in the library and if thats the case it should only take 1 second to turn on 100 LEDS.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Does seem excessive, can you provide link to library used and post code for 100 LED test?

When posting code please use the "<>" code tag in the edit menu!

 

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I used this link. However, please keep in mind I did not touch any arduino codes Im only using the codes for avr. So i used RGB Blinky. I tested multiple things but im back to my basic of rgb blinky now.

https://github.com/cpldcpu/light...

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"

struct cRGB led[24];

int main(void)
{
  DDRB = 0b00000001;
  uint8_t pixelCount = 100;
  while (1)
  {
    uint8_t i = 0;
    for (i = pixelCount; i > 1; i--){
      led[i - 1] = led[i - 2];
	}
    led[0].r = 0;
	led[0].g = 0;
	led[0].b = 255; // color code
    ws2812_setleds(led, pixelCount);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

What's the clock speed of your 328?  16MHz?

 

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

8MHZ. Im running it at fast fuses. Anything faster is out of the datasheet specs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

kepe88578 wrote:
struct cRGB led[24];

Array of 24 elements, but 100 LEDs???

 

array bounds exceeded!

 

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thats from when I was blinking more than just one color and was doing 24. But that array only relates to the different colors and doesnt have anything to do with the led count.

 

"EDIT" I dont believe it does at least.

Last Edited: Tue. Jan 15, 2019 - 02:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

kepe88578 wrote:
But that array only relates to the different colors

Maybe so, but your for loop indexes 100.  Take some time to design your test properly and repost.

Then someone may expend their time helping you trouble shoot the issue.

 

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

It does not state much. In order for me to turn on a strand of 100 it takes a solid 5 seconds. But there is not any delays other than 1 10ms delay in the library and if thats the case it should only take 1 second to turn on 100 LEDS.

You should be able to write 1 LED (24 bits) in 24 * 1.25us or 30us, so 3ms for 100 LEDs.

 

Have a look at some code I wrote for AVR8 (using internal 8 MHz clock): https://www.embeddedrelated.com/...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your stdlib file came from where? is that a standard library for arduino that you just carried over? Also here is updated code. I talked to some fellow classmates and they believe that its taking roughly 50ms for each led to turn on which makes no sense comparing to your example. 

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"

struct cRGB led[1];

int main(void)
{
  uint8_t pixelCount = 100;
  while (1)
  {
    uint8_t i = 0;
    for (i = pixelCount; i > 1; i--){
      led[i - 1] = led[i - 2];
	}
    led[0].r = 0;
	led[0].g = 0;
	led[0].b = 255; // color code
    ws2812_setleds(led, pixelCount);
  }
}

 

Last Edited: Tue. Jan 15, 2019 - 05:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

my for loop indexes 100 because thats how many LEDs im trying to turn on. so i run my for loop to count up by one led at a time and then turn them on one at a time. But it should not take ~5seconds to turn on all 100 leds. Should take roughly 3 ms.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"

struct cRGB led[1];

int main(void)
{
  uint8_t pixelCount = 100;
  while (1)
  {
    uint8_t i = 0;
    for (i = pixelCount; i > 1; i--){
      led[i - 1] = led[i - 2];
	}
    led[0].r = 0;
	led[0].g = 0;
	led[0].b = 255; // color code
    ws2812_setleds(led, pixelCount);
  }
}

 

This function is the culprit; can we see it?

 

--Mike

 

EDIT: never mind I see you posted it already.

 

Last Edited: Tue. Jan 15, 2019 - 05:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can you please post the ASM code generated for the

ws2812_sendarray_mask function?

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

my for loop indexes 100 because thats how many LEDs im trying to turn on. so i run my for loop to count up by one led at a time and then turn them on one at a time. But it should not take ~5seconds to turn on all 100 leds. Should take roughly 3 ms.

You can't just turn one one LED at a time.  You have to turn on (write to) every LED from the first to the one you are trying to turn on, so if you are trying to turn on the 80th LED you have to also write to the first 79.  And you have to do it very quickly (with essentially no delay between LED packets), or the LEDs will get confused and/or reset.

Last Edited: Tue. Jan 15, 2019 - 06:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*
* light weight WS2812 lib V2.0b
*
* Controls WS2811/WS2812/WS2812B RGB-LEDs
* Author: Tim (cpldcpu@gmail.com)
*
* Jan 18th, 2014  v2.0b Initial Version
* Nov 29th, 2015  v2.3  Added SK6812RGBW support
*
* License: GNU GPL v2+ (see License.txt)
*/

#include "light_ws2812.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
 
// Setleds for standard RGB 
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
{
   ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
}

void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
{
  ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
  _delay_us(ws2812_resettime);
}

// Setleds for SK6812RGBW
void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
{
  ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin));
  _delay_us(ws2812_resettime);
}

void ws2812_sendarray(uint8_t *data,uint16_t datlen)
{
  ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
}

/*
  This routine writes an array of bytes with RGB values to the Dataout pin
  using the fast 800kHz clockless WS2811/2812 protocol.
*/

// Timing in ns
#define w_zeropulse   350
#define w_onepulse    900
#define w_totalperiod 1250

// Fixed cycles used by the inner loop
#define w_fixedlow    2
#define w_fixedhigh   4
#define w_fixedtotal  8   

// Insert NOPs to match the timing, if possible
#define w_zerocycles    (((F_CPU/1000)*w_zeropulse          )/1000000)
#define w_onecycles     (((F_CPU/1000)*w_onepulse    +500000)/1000000)
#define w_totalcycles   (((F_CPU/1000)*w_totalperiod +500000)/1000000)

// w1 - nops between rising edge and falling edge - low
#define w1 (w_zerocycles-w_fixedlow)
// w2   nops between fe low and fe high
#define w2 (w_onecycles-w_fixedhigh-w1)
// w3   nops to complete loop
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)

#if w1>0
  #define w1_nops w1
#else
  #define w1_nops  0
#endif

// The only critical timing parameter is the minimum pulse length of the "0"
// Warn or throw error if this timing can not be met with current F_CPU settings.
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
#if w_lowtime>550
   #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
#elif w_lowtime>450
   #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
   #warning "Please consider a higher clockspeed, if possible"
#endif   

#if w2>0
#define w2_nops w2
#else
#define w2_nops  0
#endif

#if w3>0
#define w3_nops w3
#else
#define w3_nops  0
#endif

#define w_nop1  "nop      \n\t"
#define w_nop2  "rjmp .+0 \n\t"
#define w_nop4  w_nop2 w_nop2
#define w_nop8  w_nop4 w_nop4
#define w_nop16 w_nop8 w_nop8

void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
{
  uint8_t curbyte,ctr,masklo;
  uint8_t sreg_prev;
  
  ws2812_DDRREG |= maskhi; // Enable output
  
  masklo	=~maskhi&ws2812_PORTREG;
  maskhi |=        ws2812_PORTREG;
  
  sreg_prev=SREG;
  cli();  

  while (datlen--) {
    curbyte=*data++;
    
    asm volatile(
    "       ldi   %0,8  \n\t"
    "loop%=:            \n\t"
    "       out   %2,%3 \n\t"    //  '1' [01] '0' [01] - re
#if (w1_nops&1)
w_nop1
#endif
#if (w1_nops&2)
w_nop2
#endif
#if (w1_nops&4)
w_nop4
#endif
#if (w1_nops&8)
w_nop8
#endif
#if (w1_nops&16)
w_nop16
#endif
    "       sbrs  %1,7  \n\t"    //  '1' [03] '0' [02]
    "       out   %2,%4 \n\t"    //  '1' [--] '0' [03] - fe-low
    "       lsl   %1    \n\t"    //  '1' [04] '0' [04]
#if (w2_nops&1)
  w_nop1
#endif
#if (w2_nops&2)
  w_nop2
#endif
#if (w2_nops&4)
  w_nop4
#endif
#if (w2_nops&8)
  w_nop8
#endif
#if (w2_nops&16)
  w_nop16 
#endif
    "       out   %2,%4 \n\t"    //  '1' [+1] '0' [+1] - fe-high
#if (w3_nops&1)
w_nop1
#endif
#if (w3_nops&2)
w_nop2
#endif
#if (w3_nops&4)
w_nop4
#endif
#if (w3_nops&8)
w_nop8
#endif
#if (w3_nops&16)
w_nop16
#endif

    "       dec   %0    \n\t"    //  '1' [+2] '0' [+2]
    "       brne  loop%=\n\t"    //  '1' [+3] '0' [+4]
    :	"=&d" (ctr)
    :	"r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
    );
  }
  
  SREG=sreg_prev;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I understand that. But the only way i have found to address all of them quickly is the for loop. But its still very VERY slow. it takes about 5 seconds to turn on a full string of 100. But it shouldnt even be hardly noticeable to the human eye when they turn on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

I understand that. But the only way i have found to address all of them quickly is the for loop. But its still very VERY slow. it takes about 5 seconds to turn on a full string of 100. But it shouldnt even be hardly noticeable to the human eye when they turn on.

They may be resetting each time through the loop, or otherwise getting confused.  Did you look at the code link I posted?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check reply#12

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want assembler code that works, let me know.  S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does 

ws2812_setleds()

Have a built-in reset delay, or is the code just relying on the time it takes to manipulate the data array (which should work in this case, but would be dangerous in general)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Umm...

 

struct cRGB led[1];
uint8_t pixelCount = 100;
....
    for (i = pixelCount; i > 1; i--){
        led[i - 1] = led[i - 2];

Is this a typo, or are you accessing 100 elements of a 1 element array?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

im not trying to access the array at 100 elements. im using the led number in the setled function a couple lines down to set each individual light everytime the for loop goes through

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please link it below

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

im not trying to access the array at 100 elements.

Your code is doing this:

struct cRGB led[1];        
led[99] = led[98];
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay I understand that. However, regardless if i change the array number up to 100 or any large number it does not make a difference in speed. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You've misunderstood a great many things about the LEDs themselves, and the library you've chosen.

 

Try this:

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"



#define LEDS 100
#define INTERVAL_MS 1000



#define BLK (struct cRGB){ 0,   0,   0   }
#define RED (struct cRGB){ 0,   255, 0   }
#define GRN (struct cRGB){ 255, 0,   0   }
#define BLU (struct cRGB){ 0,   0,   255 }
#define CYN (struct cRGB){ 255, 0,   255 }
#define MAG (struct cRGB){ 0,   255, 255 }
#define YLW (struct cRGB){ 255, 255, 0   }
#define WHT (struct cRGB){ 255, 255, 255 }



static struct cRGB led[LEDS];



static const __flash struct cRGB colour[] = { BLK, RED, GRN, BLU, CYN, MAG, YLW, WHT };



int main(void)
{

  uint8_t l, c;

  //DDRB = 0b00000001;  // Shouldn't be needed, library takes care of it.

  // Eternal
  while (1)
  {

    // Cycle through colours.
    for (c=0; c<(sizeof(colour)/sizeof(*colour)); c++)
    {

      // All LEDs same colour.
      for (l=0; l<LEDS; l++)
      {
        led[l] = colour[c];
      }
      
      // Update physical LEDs.
      ws2812_setleds(led, LEDS);
      
      // Leave them that way for a while.
      _delay_ms(INTERVAL_MS);

    }

  }

}

 

Compiles, but untested.

 

This should give you an idea of what you need to do.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-mike wrote:

Can you please post the ASM code generated for the

ws2812_sendarray_mask function?

 

You posted the C code.  Can you compile your project

and then post the Assembler code that the compiler

produced?  Need to see the NOPs and the RJMPs and

how many are there.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
It does not state much
Go back and read the datasheet ki0bk linked to again.

Especially page 4 and 5.

 

These ws2812 leds are pretty single minded and simplstic.

You send a serial stream into them at a fixed data rate, (approx 800kbit/s from memory).

Each chip eats 24 bits, and excessive bits are buffered and shifted through to the output (page 5) to the next chip.

If the serial stream stops, then after a delay of 50us the internal registers are updated from the newly shifted in data.

 

The only difficult part for these chips is to maintain the timing, but you've probably got some breething room in the 50us between the displays.

 

If it takes 5s to update all your leds, then my guess is that all the data is send to all the leds each time you update a single led.

This is a horrible way of doing things, but arduino libraries are often written in such silly ways.

 

The good thing is that if you are able to address your led's at all, then you have some (probably asm) routine to shift out 24 bits for a RGB led.

Another good thing is that all those libraries are distributed as source code, so you can just read what happens.

It can not be very difficult to extract that part, and use it in a more sensible way.

 

When working with this it is of course very nice to have a logic analyser, so you can analyse your logic signals.

Just verifying traces in the logic analyser and comparing them with:

1). What the datasheet says they should be.

2). What's in your head.

3). What your interpretation of what the software should do.

 

... will be very educational, and you'll learn new skills on how to debug / fix software.

Some time ago I made some screenshots on how to use an USD 10 Logic analyser with free open source software to do some magic things:

https://www.avrfreaks.net/comment/2421756#comment-2421756

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:

Okay I understand that. However, regardless if i change the array number up to 100 or any large number it does not make a difference in speed. 

So an array of 10 LEDs also takes 5 seconds to fill?  If so that's a clue right there.

 

Start with an array of 2.  Cycle it 50 times in a row.  How long does that take?

 

Then an array of 4.  Cycle it 25 times in a row.  How long?

 

etc, etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting.  That library seems to fail spectacularly when F_CPU is defined with a 'U' suffix (for unsigned).

 

How are you defining F_CPU?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I get this 

RGB_blinky.c:28: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'struct'
RGB_blinky.c: In function 'main':
RGB_blinky.c:44: error: 'colour' undeclared (first use in this function)
RGB_blinky.c:44: error: (Each undeclared identifier is reported only once
RGB_blinky.c:44: error: for each function it appears in.)
make: *** [RGB_blinky.o] Error 1

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
C:\Users\GLITC\Desktop\RGB BLINKY>make flash
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -ffunction-sections -fdata-sections  -DF_CPU=8000000UL   -DBAUD=9600UL -I. -I../../AVR-Programming-Library -mmcu=atmega328p -c -o RGB_blinky.o RGB_blinky.c
avr-gcc -Wl,-Map,BLINKY.map  -Wl,--gc-sections  -mmcu=atmega328p light_ws2812.o RGB_blinky.o  -o BLINKY.elf
avr-objcopy -j .text -j .data -O ihex BLINKY.elf BLINKY.hex
avrdude -c usbtiny -p atmega328p  -U flash:w:BLINKY.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "BLINKY.hex"
avrdude: input file BLINKY.hex auto detected as Intel Hex
avrdude: writing flash (368 bytes):

Writing | ################################################## | 100% 0.40s



avrdude: 368 bytes of flash written
avrdude: verifying flash memory against BLINKY.hex:
avrdude: load data flash data from input file BLINKY.hex:
avrdude: input file BLINKY.hex auto detected as Intel Hex
avrdude: input file BLINKY.hex contains 368 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.44s



avrdude: verifying ...
avrdude: 368 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just define it in my make file. As F_CPU 8000000

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The number of LEDS does shorten the amount of time. Say i change my value to 10 leds it takes roughly half a second to fill. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I get this
It compiles fine for me, so you've made some kind of copy/paste error with the code I posted in #28.

 

Hold on, line 28 uses __flash, which isn't supported by AVR-G++.  Are you buliding this as C or C++?  What version of the toolchain (and Studio) are you using?

 

Just get rid of __flash, and try building again.  It's not really needed for this test, I just used it out of habit.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I just define it in my make file. As F_CPU 8000000
Then you shouldn't have a problem.  However, it is a serious shortcoming with the library, as 'UL' is frequently used as a suffix when defining F_CPU.  I'm looking into it now.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have a scope you can look at the data stream and figure out what's happening (where the delays are happening).  If you don't have a scope, I strongly urge you to buy or borrow one, even a simple one, for embedded work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As expected, the issue with using 'U' suffix comes down to integer promotion in the preprocessor.  The library uses a number of macros to calculate the delay required in each of three places during the bitbanging loop at the core of the library.  When F_CPU is defined as 'U', integer promotion results in overflow in a number of places.

 

Changing the library to cast each use of F_CPU to (long long) could solve the problem, but casts can't be used in conditional directives like #if, and the library makes heave use of them.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I ended up fixing it all on my own. This is the code I used. I think the issue was mainly in the function of ..._setLeds()  there must be a hidden delay somewheres for that. 

 

*EDIT* Yes. i know my pixel count says 199. that is the true value of my pixel count. im running 19 over the limit but im a risk taker oops. I was just saying 100 LEDs for simplicity sake.

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"
#define F_CPU 8000000

struct cRGB led[1];

int main(void)
{

	uint8_t pos=0;
	uint8_t direction=1;
	uint8_t i;
	uint8_t pixelCount = 199;

	led[0].r=0;led[0].g=200;led[0].b=0;		// LED 0 is red

	while(1)
    {

		for (i=0; i<pos; i++){
			ws2812_sendarray((uint8_t *)&led[0],3);
		}
		_delay_us(50);
		pos = pixelCount;
    }
}

 

Last Edited: Tue. Jan 15, 2019 - 08:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I ended up fixing it all on my own
No you didn't.  It may be 'working', but it is not 'fixed'.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I ended up fixing it all on my own.
Do you imply with that that the rest of us have been waisting our time?

 

kk6gm wrote:
If you have a scope you can look at the data stream and figure out what's happening (where the delays are happening).
A logic analyser is a much better tool for this, and I already suggested it in #30. 

In the last few hours I updated my signature (If that's what it's called). and added the text: "Doing magic with a USD 7 Logic Analyser:" and a link to some screenshots. If you like it, then give #32 in that thread some more stars. It's only got 2 votes yet.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To avoid problem when F_CPU is unsigned, one option (untested)  could be to rewrite those #if tests to avoid the possibility of any negative values.

eg. assuming A,B,C,D can't be negative, then instead of

#define w3 (A - B - C - D)
#if w3 > 0
#define w3_nops w3
#else
#define w3_nops 0
#endif

something like

#if A > (B + C + D)
#define w3_nops (A - B - C - D)
#else
#define w3_nops 0
#endif

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I dont imply that you guys were wasting your time. You guys are crazy intelligent and think about things at a deeper level than I couldve. I was able to solve my issue with a simple swap in function however I do appreciate your guys help. If it weren't for you guys I wouldn't have been looking at the particular things you pointed me to and I wouldve never solved the issue.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I dont imply
It's OK, I was just pullin' your leg. 

But please look into those USD7 logic analysers. If you had one of those you would have solved your problem before even asking on the forum, and learning how to use it and what you can do with it will make you a better engineer. Well wortth the small investment.

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
To avoid problem when F_CPU is unsigned, one option
Yup.

 

My diff:

$ diff -rupN light_ws2812.c light_ws2812_fixed.c
--- light_ws2812.c	2019-01-15 20:09:18.199438601 -0500
+++ light_ws2812_fixed.c	2019-01-15 20:08:08.572174700 -0500
@@ -55,18 +55,13 @@ void ws2812_sendarray(uint8_t *data,uint
 #define w_fixedtotal  8   

 // Insert NOPs to match the timing, if possible
-#define w_zerocycles    (((F_CPU/1000)*w_zeropulse          )/1000000)
-#define w_onecycles     (((F_CPU/1000)*w_onepulse    +500000)/1000000)
-#define w_totalcycles   (((F_CPU/1000)*w_totalperiod +500000)/1000000)
-
-// w1 - nops between rising edge and falling edge - low
-#define w1 (w_zerocycles-w_fixedlow)
-// w2   nops between fe low and fe high
-#define w2 (w_onecycles-w_fixedhigh-w1)
-// w3   nops to complete loop
-#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
-
-#if w1>0
+#define w_zerocycles    ((F_CPU * w_zeropulse              ) / 1000000000)
+#define w_onecycles     ((F_CPU * w_onepulse    + 500000000) / 1000000000)
+#define w_totalcycles   ((F_CPU * w_totalperiod + 500000000) / 1000000000)
+
+// w1_nops - nops between rising edge and falling edge - low
+#define w1 (w_zerocycles - w_fixedlow)
+#if w_zerocycles > w_fixedlow
   #define w1_nops w1
 #else
   #define w1_nops  0
@@ -74,24 +69,28 @@ void ws2812_sendarray(uint8_t *data,uint

 // The only critical timing parameter is the minimum pulse length of the "0"
 // Warn or throw error if this timing can not be met with current F_CPU settings.
-#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
-#if w_lowtime>550
+#define w_lowtime (((w1_nops + w_fixedlow) * 1000000000) / F_CPU)
+#if w_lowtime > 550
    #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
-#elif w_lowtime>450
+#elif w_lowtime > 450
    #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
    #warning "Please consider a higher clockspeed, if possible"
 #endif   

-#if w2>0
-#define w2_nops w2
+// w2_nops - nops between fe low and fe high
+#define w2 (w_onecycles - w_fixedhigh - w1)
+#if (w_onecycles + w_fixedlow) > (w_fixedhigh + w_zerocycles)
+  #define w2_nops w2
 #else
-#define w2_nops  0
+  #define w2_nops  0
 #endif

-#if w3>0
-#define w3_nops w3
+// w3_nops - nops to complete loop
+#define w3 (w_totalcycles - w_fixedtotal - w1 - w2)
+#if (w_totalcycles + w_fixedhigh) > (w_fixedtotal + w_onecycles)
+  #define w3_nops w3
 #else
-#define w3_nops  0
+  #define w3_nops  0
 #endif

 #define w_nop1  "nop      \n\t"

Initial testing is good.

 

EDIT:  The other platforms supported by the library (light_ws2812_ARM and light_ws2812_Arduino) would likely benefit from a similar patch.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Jan 16, 2019 - 01:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kepe88578 wrote:
I was able to solve my issue with a simple swap in function however I do appreciate your guys help.
Your 'solution' will blow up in your face sooner or later.  As soon as you enable interrupts, for example.

 

Take the time now to understand how to use the library correctly before you end up wasting your time later trying to chase down a ghost.  Look again at #28 (omitting __flash).  I haven't tested it on hardware, but it does compile and a casual look at the .lss suggests it should do what it says on the tin.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

The WS2812 LEDs are individually addressable in series. It means that a serial protocol is used to configure them. You must send as much 8-bit data as your number of LEDs. Each LED will strip one byte from your string and pass what's left to the next one.

There is an interesting example project built using Microdevt: https://www.kw-net.com/en/projects/

The driver in this project allows to configure the LEDs even on a micro-controller with little memory such as attiny85. To do so it stores data for only a few LEDs and sends multiple times that data. In result all the LEDS can be addressable.

BR

Krzysztof Witek
https://www.kw-net.com