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\$
  • \$\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 '18 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 '18 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 '18 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 '18 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\$ – Peter Smith May 19 '18 at 17:11
0
\$\begingroup\$

Alright, finally figured it out. 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.

Guess I'm still figuring out some Atmel Studio stuff. 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\$
  • \$\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\$ – Chris Stratton Jan 25 '19 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 '19 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\$ – Chris Stratton Jan 25 '19 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\$ – Chris Stratton Jan 25 '19 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 '19 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.