IR NeoPixel Controller Dongle
21st July 2026
This is a NeoPixel driver, controlled by an infrared remote control, that fits on a small USB dongle that plugs into a USB-C power adapter to power the LEDs:
![]()
The IR NeoPixel Controller, based on a Microchip AVR16DD20, plugs into a USB-C power adapter.
It will drive a chain of several high-power NeoPixel LEDs; for example, to provide controllable illumination in a room. The IR remote control lets you control the hue, saturation, and brightness of each RGB LED independently, or alternatively set them all to the same settings. You can also switch off and on all the lights, or animate the lights with slowly-changing hue.
A status LED on the board gives feedback about the settings, and the settings are stored in EEPROM, so if you disconnect and reconnect the power the LEDs remember their previous settings.
It's based on an AVR16DD20 and a TSOP6138 infrared receiver module, and is a PCB version of my earlier project IR NeoPixel Controller.
Design
The circuit consists of four components: the NeoPixel LEDs, a USB-C power adapter, the NeoPixel driver, and the IR remote control receiver.
High-power NeoPixel LEDs
For the LEDs I chose Adafruit's 3 watt chainable NeoPixel LEDs, that use WS2811 NeoPixel-protocol controllers to drive a high-power RGB LED mounted on an aluminium heatsink [1]. To use these leave the #define at the start of the program set to RGB.
Alternatively you can use the 4 watt RGBW versions [2], which are available in warm white, natural white, or cool white. To use these set the #define at the start of the program to RGBW.
Warning! These high-power NeoPixel LEDs are extremely bright. When using them for room illumination I recommend using a reflector to direct them at the ceiling, or a translucent globe light fitting [3].
The high-power LEDs should be mounted on a heatsink to avoid overheating at maximum brightness; they shouldn't get too hot to touch comfortably. I used a square 50 x 50 x 15mm black finned heatsink, available from eBay or AliExpress [4].
The IR NeoPixel Controller Dongle will also drive standard WS2812 or WS2812B NeoPixel LEDs daisy-chained together. To control more than nine LEDs change the value of NumPixels at the start of the program.
Power adapter
The IR NeoPixel Controller Dongle is designed to plug into a USB-C power adapter to derive the 5V supply it needs. I used the Apple A2344 20W power adapter which provides 5V at 3.0A, and is beautifully designed with folding prongs for UK power sockets:
![]()
The IR NeoPixel Controller Dongle powered by an Apple USB-C power adapter,
and controlling a high-power 3W NeoPixel RGB LED.
All USB-C power adapters provide 5V at at least 1.5A, so any make or model should be suitable.
NeoPixel driver
To drive the LED modules I used a version of my NeoPixel driver described in the earlier article NeoPixel Driver Program 3. This uses a Timer/Counter in the AVR processor to generate the waveforms needed by the NeoPixel protocol, and the SPI peripheral to output them as a serial stream, rather than the software approach used by many other NeoPixel interfaces. It's capable of driving up to about 160 NeoPixel displays, subject to the power available from the power adapter, but by default the IR NeoPixel Controller Dongle program limits it to nine to match the number of buttons available on the IR remote.
IR remote control receiver
The IR remote control receiver is designed to work with remote controls that use the NEC protocol, like many low cost infrared remotes available from the Far East. The remote control I used is available from Adafruit [5], or their distributors such as The Pi-Hut in the UK [6]. The NEC protocol is also used by the Apple Remote [7], so if you have one of those you could use it. If you want to use a different remote control you can find its key codes as described below: Finding the codes for an IR remote.
Using the IR NeoPixel Controller
The following diagram shows the function of each key on the Adafruit remote control:

Initially all the LEDs will be off, at minimum brightness, the saturation will be at maximum, and the remote control will control the first LED.
- To control an individual LED press the corresponding number key, 1 to 9. To control all the LEDs press 0.
- To control the brightness press or hold down ▲ or ▼. The status LED flashes when you reach minimum or maximum brightness.
- To change the hue (colour) press or hold down ◀ or ▶. The hue goes in the sequence: red, yellow, green, cyan, blue, magenta, and back to red.
- To change the saturation press or hold down VOL- or VOL+. Reducing the saturation dilutes the colour with white. The status LED flashes when you reach minimum or maximum saturation.
- To turn off all the NeoPixels press STOP. Press it again to revert to their previous settings.
- To animate the hue press ▶||. The hue will change slowly over a period of two minutes. Press ▶|| to turn off the animation. Adjusting the hue also cancels the animation.
The settings are saved automatically every 10 seconds.
The circuit
Here's the circuit of the IR NeoPixel Controller PCB:
![]()
Circuit for the IR NeoPixel Controller Dongle.
Infrared receiver
The circuit uses an SMD version of the popular TSOP38238 38kHz infrared receiver module, the TSOP6138.
Microcontroller
To fit the circuit on a small PCB I switched from the 14-pin SOIC processor used in the breadboard version to a VQFN AVR16DD20. Despite having more pins this is substantially smaller; in fact it's one of the smallest processors Microchip manufacture, at only 3mm square. You could also use a VQFN AVR32DD20.
Here's the parts list (click to expand):
Parts list
| Qty | Item | Value | Size | Typical parts |
| 1 | SMD resistor | 220Ω | 0805 | Yageo RC0805JR-07220RL |
| 1 | SMD resistor | 330Ω | 0805 | Yageo RC0805JR-07330RL |
| 1 | SMD resistor | 470Ω | 0805 | Yageo RC0805JR-07470RL |
| 1 | SMD resistor | 5.1kΩ | 0805 | Yageo RC0805JR-075K1L |
| 1 | Ceramic capacitor | 0.1µF | 0805 | Yageo CC0805KRX7R8BB104 |
| 1 | Ceramic capacitor | 100µF 10V | 1210 | GRM32ER61A107ME20L |
| 1 | LED | Red | 0805 | |
| 1 | Microcontroller | AVR16DD20 | VQFN-20 | AVR16DD20T-I/REB |
| 1 | IR receiver | TSOP6138 | TSOP6138 | |
| 1 | USB-C | SMD | Plug | Edge-Launch USB Type C SMT Plug |
| 1 | Terminal Block * | 3-way | 0.1" Pitch | TBC05-03-1-G-G |
| 1 | PCB | Double-sided | 14.0 x 22.2mm |
* Optional
Construction
I designed a PCB in Eagle and sent it to PCBWay for production. There's a link at the end of the article if you want to make yourself some boards.
The VQFN package is very tricky to solder because the spacing of the pads is only 0.4mm. I recommend soldering it on its own, before adding the other components, as follows:
- Use a pin to make a thin worm of solder paste along the four rows of pads. I use Chip Quik SMD291AX10T3 solder paste. Time spent getting the line of solder paste thin and even saves time later sorting out solder bridges. Also put a dot of solder paste on the centre pad of the chip. Then drop the chip in place with a pair of tweezers, if necessary giving it a few taps to position it. I use Rhino SW-11 tweezers [8].
- Melt the solder with a hot air gun or hotplate. I use a Miniware MHP50-B5 50x50mm hotplate [9] [10] at 235°C.
- When it has cooled down examine the result under a magnifying glass to check for any solder bridges. I use an Engineer illuminated PCB inspection loupe [11].
Then add the remaining components. When placing the USB-C connector put a blob of solder paste on each of the eight square pads, as these anchor the connector to the board. I used a spare board to support the front of the USB-C connector on the hotplate.
Testing
My recommended procedure for testing the board is as follows:
- Connect +5V and GND to the appropriate terminals at the base of the board while monitoring the current consumption. With a fresh AVR16DD20 the current should be about 1.2mA. Substantially more indicates a possible solder bridge. Substantially less probably indicates a poor connection to the VCC or GND pins on the AVR16DD20.
- Connect a UPDI programmer to the +5V and GND terminals at the base of the board and the UPDI terminal at the edge of the board, and do Burn Bootloader as described below in Installing the program. This checks that UPDI programming succeeds.
- Upload the following test program which checks the connection to the Status LED and NeoPixel DI output, and the link between PA1 and PA6:
void setup() {
pinMode(PIN_PC3, OUTPUT);
pinMode(PIN_PD5, OUTPUT);
pinMode(PIN_PA1, OUTPUT);
pinMode(PIN_PA6, INPUT);
}
void loop() {
digitalWrite(PIN_PA1, HIGH);
digitalWrite(PIN_PD5, digitalRead(PIN_PA6));
digitalWrite(PIN_PC3, HIGH);
delay(1000);
digitalWrite(PIN_PA1, LOW);
digitalWrite(PIN_PD5, digitalRead(PIN_PA6));
digitalWrite(PIN_PC3, LOW);
delay(1000);
}
The LED should flash, and the NeoPixel output DI should toggle between VCC and GND.
- Plug the USB-C connector into a USB-C breakout board [12] and check for continuity between the USB GND pin and the – pin on the terminal block, and between the USB VBUS pin and the + pin on the terminal block.
- Upload the IR NeoPixel Controller program, connect a NeoPixel, plug the USB-C connector into a USB-C power adapter, and check that you can control the NeoPixel with an IR remote control.
I built three prototypes, and the most common problem I found was a pin on the microcontroller or USB-C connector not making contact with the corresponding pad. The solution is to put a small blob of solder paste on the edge of the pad, where it extends beyond the microcontroller, and then reflow it on the hotplate.
The program
The program is essentially the same as the breadboard version described in IR NeoPixel Controller, but with the following changes to reflect the fact that it's based on the AVR16DD20 in a 20-pin VQFN package:
- The IR Receiver is now connected to PC2, so the statement to configure the pin-change interrupt needs to change to:
PORTC.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;// Interrupt falling edge
The Interrupt Service Routine needs to change to PORTC_PORT_vect, and the interrupt flag is cleared with:
PORTC.INTFLAGS = PIN2_bm; // Clear interrupt flag
- On the AVR16DD20 we can use the default positions of MOSI, MISO, SCK, and SS on PA4 to PA7, so the following statement isn't necessary:
PORTMUX.SPIROUTEA = PORTMUX_SPI0_ALT4_gc; // PD4, PD5, PD6, PD7
and the MISO pin is configured as an output with:
PORTA.DIRSET = PIN5_bm; // MISO output
- Now that MISO is on PA5 we have to use events CHANNEL0 to copy it to LUT1 IN2:
EVSYS.CHANNEL0 = EVSYS_CHANNEL0_PORTA_PIN5_gc; // Link PA5 ... EVSYS.USERCCLLUT1A = EVSYS_USER_CHANNEL0_gc; // ... to LUT1 EVENTA
- We need to use events to copy PC1 to PA7, with:
PORTMUX.EVSYSROUTEA = PORTMUX_EVOUTA_ALT1_gc; // EVOUTA on PA7 EVSYS.CHANNEL3 = EVSYS_CHANNEL3_PORTC_PIN1_gc; // Link PC1 ... EVSYS.USEREVSYSEVOUTA = EVSYS_USER_CHANNEL3_gc; // ... and PA7
- The status indicator LED is on PD5 on this circuit, so it needs to be set as an output with:
PORTD.DIRSET = PIN5_bm; // PD5 Status output
and the routine to toggle it is:
void Status (bool on) {
if (on) PORTD.OUTSET = PIN5_bm; else PORTD.OUTCLR = PIN5_bm;
}
Otherwise the program is the same.
Installing the program
First install Spence Konde's DxCore from GitHub: see DxCore - Installation. I used version 1.5.11 [13].
Then, in the Arduino IDE:
- Choose the AVR DD-series (no bootloader) option under the DxCore heading on the Board menu.
- Check that the subsequent options are set as follows (ignore any other options):
Board: "AVR DD-series (no bootloader)"
Chip: "AVR16DD20"
Clock Speed: "24 MHz internal"
You can leave the other options at their defaults, the first option on each submenu.
- Connect a UPDI programmer to the UPDI pin on the side of the PCB, and the GND and VDD pins on the terminal block.
To program the processor the recommended option is to use a 5V or 3.3V USB to Serial board, such as the SparkFun FTDI Basic board [14], or a USB to Serial cable [15], connected with a Schottky diode as follows. You can substitute a 4.7kΩ resistor for the Schottky diode:

- Set Programmer to the "SerialUPDI - Normal: 230400 baud (recommended)" option.
- Select the USB port corresponding to the USB to Serial board in the Port menu.
- Select Burn Bootloader to reset the fuses to their defaults.
- Click Upload to upload the program to the AVR16DD20.
Resources
Here's the IR NeoPixel Controller Dongle program: IR NeoPixel Controller Dongle Program.
Get the Eagle or Gerber files for the PCB here: https://github.com/technoblogy/ir-neopixel-controller.
Or order boards from OSH Park here: IR NeoPixel Controller.
- ^ Ultra Bright 3 Watt Chainable NeoPixel LED on Adafruit.
- ^ Ultra Bright 4 Watt RGBW NeoPixel LED on Adafruit.
- ^ Firstlight Sphere 15cm Flush Ceiling Light on Lightbulbs Direct.
- ^ High Quality 50*50*15MM New Aluminum Heatsink on AliExpress.
- ^ Mini Remote Control on Adafruit.
- ^ Mini IR Remote Control on The Pi Hut.
- ^ Apple Remote on Wikipedia.
- ^ Rhino SW-11 Tweezers on Adafruit.
- ^ MHP50-B5 on Adafruit.
- ^ MHP50-B5 on AliExpress.
- ^ Engineer SL-71 Illuminated PCB Inspection Loupe on The Pi Hut.
- ^ USB Type C Breakout Board on Adafruit.
- ^ There is a problem programming the AVR16DD20 with DxCore 1.6.2.
- ^ SparkFun FTDI Basic Breakout - 5V on Sparkfun.
- ^ FTDI Serial TTL-232 USB Cable on Adafruit.
blog comments powered by Disqus
