0
\$\begingroup\$

I am working on a small LED board project. The LED board is a 16x16 panel of WS2818B LEDs; they are also known as Neopixels. Controlling these thing is a bit of a pain, and I thought I would look and see if there were some sort SPI interface. I struck gold at Wayne Holder's page who provides a small assembly language program for the ATTiny10, and this looks almost perfect.

The problem here is that I want to do this with through-hole parts. So I bought some ATTiny85s off of Amazon. I don't know much about AVRs beyond some basic Arduino projects, but I think I ported Holder's program over correctly:

;               +====+
;    Vcc -> PB5 |*   | Vcc
;     NC <- PB3 |    | PB2 <- CLK
;   LEDs -- PB4 |    | PB1 -- NC
;           GND |    | PB0 <- MOSI
;               +====+

MOSI =      0x00            ; PB0
SCLK =      0x02            ; PB2
DOUT =      0x04            ; PB4

CLKPR =     0x26
PORTB =     0x18
DDRB =      0x17
PINB =      0x16

.global main                ; It's just easier to call it main

main:
    eor     r17,  r17       ; Set Clock Prescaler to 1:1 (CLKPR = 0)
    out     CLKPR, r17

    sbi     DDRB, DOUT      ; Set PB2 as Output

waithi:
    sbis    PINB, SCLK      ; Wait for CLK to go HIGH (rising edge)
    rjmp    waithi

    sbi     PORTB, DOUT     ; Set Output HIGH to begin pulse to WS2818b and
    nop                     ; and pause for a cycle

    sbis    PINB, MOSI      ; Skip if DIN "1" bit
    cbi     PORTB, DOUT     ; Set Output LOW to end "0" bit pulse to WS2818b
    nop                     ; and pause for three cycles
    nop
    nop

    cbi     PORTB, DOUT     ; Set Output LOW to end "1" bit pulse to WS2818b

waitlo:
    sbic    PINB, SCLK      ; Wait for CLK to go LOW (falling edge)
    rjmp    waitlo

    rjmp    waithi          ; Return to wait for SCLK to go HIGH

The idea is I should be able to drive this with an Arduino. Using an old Arduino Leonardo clone I had laying around, I connected it up. The problem is, no matter what I send out on the SPI to the ATTiny85, it lights up something around the first 12-20 lights in bright white. This is the Leonardo code:

#include <SPI.h>

#define VALU 0x20
#define PIXELS 256
#define CLKRATE 500000
#define LED_PIN 13

void setPixel(RGB color);

void setup() {
    SPI.begin();
    noInterrupts();
    SPI.beginTransaction(SPISettings(CLKRATE, MSBFIRST, SPI_MODE0));
    for (int ii = 0; ii < PIXELS; ii++) {
        setPixel(RGB(0x00, 0x00, 0x00));  // Blk
    }
    SPI.endTransaction();
    interrupts();
    delay(1000);

    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    digitalWrite(LED_PIN, HIGH);
    noInterrupts();
    SPI.beginTransaction(SPISettings(CLKRATE, MSBFIRST, SPI_MODE0));
    for (int ii = 0; ii < PIXELS; ii++) {
        SPI.transfer(0);
        SPI.transfer(0x10);
        SPI.transfer(0);
    }
    SPI.endTransaction();
    interrupts();
    digitalWrite(LED_PIN, LOW);
    delay(1000);

    digitalWrite(LED_PIN, HIGH);
    noInterrupts();
    SPI.beginTransaction(SPISettings(CLKRATE, MSBFIRST, SPI_MODE0));
    for (int ii = 0; ii < PIXELS; ii++) {
        SPI.transfer(0);
        SPI.transfer(0);
        SPI.transfer(0);
    }
    SPI.endTransaction();
    interrupts();
    digitalWrite(LED_PIN, LOW);
    delay(1000);
}

I flash the LED on the Leonardo just so I can see when it does something. Here's a picture of the panel doing what it does:

LED Panel

Now, I have a KKMoon multimeter, and if I am reading this correctly, it is showing a pulse width on the output pin from the ATTiny85 to the LED matrix of like 4us. This is the short pulse. The longer one is longer. But the appropriate length for the short pulse for the WS2818B is 0.4us.

Multimeter image

At this point, I feel like I have a timing issue. As a last-ditch effort, I checked the fuses, and the values shown are:

fuses_lo = 0x62
fuses_hi = 0xdf
fuses_ext = 0xff
lock_byte = 0xff

Checking back against the ATTiny85 datasheet, the chip should be running at 8MHz. That should mean a NOP length of 150ns. Obviously, something is not working the way I think it should, but I am lost now. I would appreciate any advice as to what is going wrong and how to fix it.

Thanks!

\$\endgroup\$
1
  • \$\begingroup\$ The signal in the scope is a 3.3V pulse. What supply the MCU uses? The LEDs need a 5V data signal to work, they may not work with a 3.3V data signal (depends on tolerances). \$\endgroup\$
    – Justme
    Commented Feb 5, 2021 at 5:18

1 Answer 1

1
\$\begingroup\$

You do have a timing problem, but should be easy to fix.

First a suggestion - why do you need that ATTINY at all? Why not drive the Neopixel directly from the Arduino? There are lots of code examples that will work out of the box, including the popular Adafruit library.

If you really need to get the ATTINY driving the Neopixels then you will need to get your timing right between the code and the clock setting on the ATTINY so that your pulses are the correct width. You can read more about the actual timing requirements here.

The first thing I would check in your case is the clock prescaller bits in register CLKPR...

enter image description here

If you set them all to zeros then the clock should be 8Mhz and you should be able to generate the correct timing signals.

Looking at your fuse settings, it looks like you are programming the CKDIV8 fuse, which initializes the above bits to divide the clock by 8 - resulting in a 1 Mhz clock which would result in a minimum possible pulse width of 1us ( set bit immediately followed by clear bit, 1 cycle each), which would be too wide for neopixels.

So you can try use 0xE2 and then checking your pulse width again and see if that fixes it. Make sure the ATTINY has sufficient voltage to run at 8Mhz (2.7V)...

enter image description here

...or it may crash. This is why the default is to boot up at 1Mhz, so you can have a chance to check to make sure voltage is good enough to jump to the higher speed.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In the interest in karma, 0xE2 is the solution. I get a beautiful pulse of the right density, so thank you. I have, unfortunately, exposed new problems, but these I am still working on on my own...Thank you so much! \$\endgroup\$ Commented Feb 8, 2021 at 1:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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