2
\$\begingroup\$

So I'm trying to run some SK6812 (WS2812 clones) on a standalone ATMega328p.

The output signal is too slow! I define F_CPU as 8000000 (8Mhz), both in the code and in the Atmel Studio Symbols, but my signal is slow by a factor of 10. The LED is always white, instead of red as the code intends.

#ifndef F_CPU
#define F_CPU 8000000UL // 8 MHz clock speed
#endif

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

#include "light_ws2812.h"

struct cRGB led[1];

int main(void)
{


    while(1)
    {
        led[0].r=25;led[0].g=00;led[0].b=0;    // Write red to array
        ws2812_setleds(led,1);
        _delay_ms(500);                         // wait for 500ms.

        //led[0].r=0;led[0].g=25;led[0].b=0;            // green
        //ws2812_setleds(led,1);
        //_delay_ms(500);

        //led[0].r=0;led[0].g=00;led[0].b=25;       // blue
        //ws2812_setleds(led,1);
        //_delay_ms(500);
    }
}

Fuses are l:0xA2, h:0xD9, e:0x07. This should correspond to an internal 8Mhz clock (verified on B0 with oscilloscope). Here's what I get for a data signal on B4:

enter image description here

The data looks fine (00000000 for green, then 00011001 (25d) for red). However the period is about 12µs, but according to the SK6812 datasheet, the period must be 1.25µs ± 150ns:

enter image description here

There's not much to show on the schematic, but to be thorough: enter image description here

And like I said before, the intended header for data (D6) didn't output anything, so I had to use B4 since it was also broken out to a header.(Connectivity issue, I figured it out)

Any help is appreciated!

\$\endgroup\$
6
  • \$\begingroup\$ I'm a little confused. Are you using library code? Or are you directly programming the chip yourself to get the hardware configured and operating correctly? This phrase, "according to the datasheet," bothers me. A datasheet is about the MCU. It tells you nothing about a library. \$\endgroup\$
    – jonk
    May 18, 2018 at 21:30
  • \$\begingroup\$ @jonk I'm using example code from the library, modified slightly to simplify troubleshooting (just commenting out those few lines). The datasheet is for the SK6812 LED, sorry if that wasn't clear, I'll edit it in. The library is made to drive the specific timing of those LEDs. \$\endgroup\$
    – Orotavia
    May 18, 2018 at 21:35
  • 2
    \$\begingroup\$ Setting #define F_CPU 8000000UL only calibrates the standard library busy loops. You have to flip the fuses when programming the AVR to select the clock source and frequency (also, do not forget the CLKDIV8 fuse!) \$\endgroup\$
    – Janka
    May 18, 2018 at 22:12
  • \$\begingroup\$ @Janka I've got the fuses set for 8Mhz: "Fuses are l:0xA2, h:0xD9, e:0x07. This should correspond to an internal 8Mhz clock (verified on B0 with oscilloscope)" Am I missing something more? \$\endgroup\$
    – Orotavia
    May 19, 2018 at 16:29
  • 2
    \$\begingroup\$ You do realise that 1.25usec is only 10 machine cycles at 8MHz? You might struggle to achieve a toggle at that rate even with hand crafted assembly. \$\endgroup\$ May 19, 2018 at 17:11

1 Answer 1

1
\$\begingroup\$

In Atmel Studio, doing a
#define F_CPU 8000000UL
at the beginning of main.c was not sufficient. I've gotten rid of that code, and created a Defined Symbol
F_CPU=8000000UL
under

Toolchain>AVR/GNU C Compiler>Symbols.

I'm still not really sure why defining F_CPU before even calling the libraries was erroneous; even util/delay threw some warnings sometimes (if I had F_CPU as an Undefined symbol, I think).

\$\endgroup\$
5
  • \$\begingroup\$ A #define applies only to the file in which it is found. For something to apply to a whole project it would typically be placed in a header file that all source files explicitly #include, either directly or as a result of being included by another header file that is. \$\endgroup\$ Jan 25, 2019 at 15:39
  • \$\begingroup\$ @ChrisStratton This is not correct. #define A B means "From now on, replace any A by B in the following code". Since #include foo means "Paste the content of file foo here", a define is valid also in files included after, and defines inside included files are valid in the current file below the include directive. \$\endgroup\$
    – sweber
    Jan 25, 2019 at 17:06
  • 1
    \$\begingroup\$ Actually, it is correct - as you've just agreed, it only applies in files where it is either stated or included (a process which as you explain literally includes the content of that file - thus inheriting anything defined or included before). The asker's self-alleged problem is because it does not apply to other C/C++ source files which do not state or include it. In the Arduino realm however there's some hidden mumbo jumbo like concatenating all the .ino files together into a single source to feed the compiler's pre-processor, which can lead to expectations of non-standard behavior. \$\endgroup\$ Jan 25, 2019 at 18:26
  • \$\begingroup\$ However Peter Smith's comment above makes it questionable that this is even the cause of slow behavior; if it's the solution it may be that it causes the delay to become a no-op. But it would be interesting what the actual output frequency achieved now is. My guess is that it would still be wrong, but perhaps close enough to now work. \$\endgroup\$ Jan 25, 2019 at 18:27
  • \$\begingroup\$ @ChrisStratton Yup, the library I'm using does produce non-exact timing. This site actually describes the process, moreso than I've looked into, but they explain a 7:3 clock cycle ratio for a '1' and 3:7 for a '0' at 8MHz (1.25us). Haven't hooked up a scope to confirm, but it works nonetheless. \$\endgroup\$
    – Orotavia
    Jan 25, 2019 at 23:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.