Topics

► Games

► Sound & Music

► Watches & Clocks

► Wireless

► GPS

► Power Supplies

► Computers

► Graphics

► Thermometers

► Wearables

► Test Equipment

► Tutorials

► Libraries

► PCB-Based Projects

By processor

AVR ATtiny

► ATtiny10

► ATtiny2313

► ATtiny814

► ATtiny84

► ATtiny841

► ATtiny85

► ATtiny861

► ATtiny88

AVR ATmega

► ATmega328

► ATmega1284

AVR 0, 1, and 2-series

► ATmega1608

► ATmega4808

► ATmega4809

► ATtiny1604

► ATtiny1614

► ATtiny202

► ATtiny3216

► ATtiny3224

► ATtiny3227

► ATtiny402

► ATtiny404

► ATtiny414

► ATtiny814

AVR DA/DB/DD-series

► AVR128DA28

► AVR128DA32

► AVR128DA48

► AVR128DB28

► AVR128DB48

► AVR64DD14

ARM

► ATSAMD21

► RP2040

► RA4M1

About me

  • About me
  • Twitter
  • Mastodon

Feeds

RSS feed

A NeoPixel Driver using AVR Hardware [3]

26th August 2025

My previous two articles described a driver for NeoPixel (WS2812) LED displays using the peripherals on an AVR128DA28 processor, and showed how to eliminate most of the interconnections between the pins on that circuit by taking advantage of the AVR Event System.

This third article shows how to go one step further, and fit the same NeoPixel Driver on a processor with half the number of pins, the 14-pin AVR64DD14:

NeoPixelDriver14.jpg

NeoPixel Driver implemented using the hardware peripherals and Event System
in a 14-pin AVR64DDD14.

Introduction

My earlier article A NeoPixel Driver using AVR Hardware [1] described a program for AVR processors that created the stream of pulses needed by the NeoPixel protocol using the SPI peripheral in conjunction with a Timer/Counter Type A and the Configurable Custom Logic. The next article A NeoPixel Driver using AVR Hardware [2] showed how to use another feature of the AVR processors, the Event System, to replace most of the external wires on this circuit by internal connections defined using event channels. This not only saved wires on the circuit board, but also freed up some of the pins so they could be used for other functions.

After doing this I realised that this makes it possible to fit the NeoPixel Driver on a processor with half the number of pins, the 14-pin AVR64DD14.

This may seem impossible; after all, we're using an SPI peripheral (four pins), two outputs from a Type A Timer/Counter (two pins), three inputs and an output in a Look-Up Table (four pins), an error LED (one pin), and an enable output (one pin), making a total of 12 pins, and that's without counting the power, UPDI, and Reset pins (four more pins)!

What makes it possible is that you can still use all three inputs and the output of a LUT, even if some of those signals don’t correspond to physical pins. So, although the AVR64DD14 doesn't bring all the inputs of Look-Up Table LUT1 to external pins, we can still connect to it using Events and use it to combine the WO0, WO1, and MISO signals as in the AVR128DA28 version.

The circuit

Here's the circuit that uses Events to fit the same NeoPixel Driver using AVR hardware onto a 14-pin AVR64DD14:

NeoPixelDriver8.gif

NeoPixel Driver using the hardware peripherals and Event System in an AVR64DD14.

The AVR64DD14 is only available in a surface-mount SOIC-14 package, so I mounted it on an Adafruit breakout board [1] to fit it on a mini-breadboard; see the photograph at the beginning of this article. The lower memory AVR32DD14 or AVR16DD14 would work equally well.

To demonstrate the program I've used a 12 NeoPixel ring from Adafruit [2].

The program

The changes to the original version of the NeoPixel Driver for the AVR64DD14 are described below:

SPI peripheral

The following lines select the alternative position of the SPI0 peripheral, using pins PD4, PD5, PD6, and PD7, and define the MISO pin PD5 as an output:

  PORTMUX.SPIROUTEA = PORTMUX_SPI0_ALT4_gc;               // PD4, PD5, PD6, PD7
  PORTD.DIRSET = PIN5_bm;                                 // MISO output 

Timer/Counter Type A

No changes are needed to the configuration of Timer/Counter TCA0 as it's used in its default position with the waveform outputs WO0 and WO1 on PA0 and PA1 respectively.

Configurable Custom Logic (CCL)

No change is needed to the configuration of the CCL Look-Up Table LUT1 as it's used in its default position with 1,OUT on PC3. On the AVR64DD14 1,IN0 is not available on an external pin, but this is not a problem because we can use the Event System to connect to it internally.

Connecting the TCA0 waveform outputs to the look-up table

In the original circuit there were connections between the Timer/Counter waveform outputs WO0 (PA0) and WO1 (PA1), and the LUT1 inputs IN0 (PC0) and IN1 (PC1). These can be eliminated by defining them in the LUT1 configuration as follows:

  CCL.LUT1CTRLB = CCL_INSEL0_TCA0_gc | CCL_INSEL1_TCA0_gc;// TCA0 WO0 and WO1
  CCL.LUT1CTRLC = CCL_INSEL2_EVENTA_gc;                   // LUT1 EVENTA
  CCL.TRUTH1 = 0b11001010;
  CCL.LUT1CTRLA = CCL_OUTEN_bm | CCL_ENABLE_bm;           // Enable, output on PC3

This replaces the two wires between WO0 and PD0, and WO1 and PD1, by TCA0 events.

In addition we specify that IN2 comes from LUT1 EVENTA instead of from the external input PC2.

Connecting the SPI MISO pin to LUT1

We will use event channel 2 to eliminate the wire between MISO (PD5) and IN2. The first half of this connection was defined in the configuration of LUT1 above. The second half is defined as follows:

  EVSYS.CHANNEL2 = EVSYS_CHANNEL2_PORTD_PIN5_gc;          // Link PD5 ...
  EVSYS.USERCCLLUT1A = EVSYS_USER_CHANNEL2_gc;            // ... to LUT1 EVENTA

Connecting PD4 to the SPI SS pin

Finally, we will use event channel 3 to connect between SS (PD7) and the EN output PC1:

  PORTMUX.EVSYSROUTEA = PORTMUX_EVOUTA_ALT1_gc;           // EVOUTA on PA7
  EVSYS.CHANNEL2 = EVSYS_CHANNEL2_PORTD_PIN4_gc;          // Link PD4 ...
  EVSYS.USEREVSYSEVOUTA = EVSYS_USER_CHANNEL2_gc;         // ... and PA7

Connecting the TCA0 WO1 output to the SPI SCK pin

The one wire that remains in the circuit is the connection between WO1 (PA1) and SCK (PD6), as there doesn't seem to be a way of implementing it using events.

EN and Error outputs

Finally, we use PC1 and PC2 as the EN and Error outputs respectively, and they are configured with the following statements:

  PORTC.OUTSET = PIN1_bm;
  PORTC.DIRSET = PIN1_bm;                                 // PC1 EN output high
  PORTC.DIRSET = PIN2_bm;                                 // PC2 Error output low

Resources

Here's the version of the NeoPixel Driver for the AVR64DD14: NeoPixel Driver Program 3.


  1. ^ SMT Breakout PCB for SOIC-14 or TSSOP-14 on Adafruit.
  2. ^ NeoPixel Ring - 12 x 5050 RGB LED on Adafruit.

blog comments powered by Disqus