To complete this week i had to build an ATtiny44 board because during week 6 i developed an ATxMega board instead of an ATtiny one.
In our lab we have a delta printer with some Neopixel LED strips but they have never been connected so i made a board for them.
Neopixel are not normal RGB LEDs but inside they have an integrated circuit, WS2812, the latter take care of choosing the color of the LED.
Every LED have an input and an output pin, they are serialized connecting the output of the first to the input of the next and so on.
The board have 3 output header ( for the 3 strips on the 3d printer ) all connected to the same PWM output pin of the ATtiny ( pin #6 named PA7 ) and an analog pin to connect a potentiometer which will regulate the brightness or the color of the strips.
I designed the board with EAGLE, created the gcode with the mods.cba.mit.edu and etched/cutted the board with a Roland SRM-20 cnc.
After soldering the board i realized that i forgot to place a resistor between the PA7 pin and led output so i used a cutter to separate the bus and i soldered a resistor.
To test if everything was working i connected the ATtiny44 board to the FabOptimus ISP programmer i made during week 4 and loaded the arduino bootloader into the board.
Before loading the bootloader i “installed” the ATtiny boards.txt through the Arduino IDE’s Board Manager. After i downloaded and installed the FastLED library http://fastled.io/.
I created a simple sketch to light every led at a fixed RGB color ( green ) and change the luminosity through the potentiometer. To test the board i used a spare 3 LED Neopixel strip.
Before uploading the code i had to select from the Arduino IDE’s “tool” dropdown menu the following settings:
As you can see from the image below the sketch + the bootloader take 94% of the ATtiny44 space ( 4Kb total ) which is a lot!!
From the previous weeks i had the avrdude and gcc environment already setupped.
I found the WS2812 library here https://github.com/cpldcpu/light_ws2812
To convert the Arduino code to C code i had first to understand how the ATtiny’s ADC is handled.
All the I/O pins of the ATtiny44 have multiple functions ( you can see them in the image above ) and they are “grouped” into ports.
Specifically the tiny44 have PORT A and PORT B each port have 3 registers: DDR, PORT and PIN. They are 8 bit registers ( attiny44 is 8bit architecture ) and each bit correspond to a pin of the attiny.
To use the ADC we have to configure 2 registers:
REFS0, REFS1 and REFS2 are used to select the reference voltage, the table below shows the available combinations.
In my case i used the internal 2.56V reference voltage.
ADLAR - ADC Left Adjust Result is a bit used to Left or Right adjust the ADC output. Write one to left adjust or zero to right adjust.
MUX[3:0] - Analog Channel and Gain Selection Bits are used to select the pin we want to read the analog input and the gain.
Here’s the resulting code:
#include < util/delay.h >
#include < avr/io.h >
#include < avr/interrupt.h >
#include "light_ws2812.h"
#define NUM_LEDS 6 // Total strip LED number
struct cRGB led[NUM_LEDS];
int brightness = 0; // Variable to hold the brightness
uint8_t ADCLow; // ADCL variable
uint16_t ADCFull; // ADCL + ADCH variable
int main(void)
{
int i = 0;
ADMUX |= (0 << REFS0); // set the voltage reference
ADMUX |= (0 << REFS1); //
ADMUX |= (0 << ADLAR); // left adjust the result
ADMUX |= (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0); // select the ADC pin ADC1 PB2
ADCSRA |= (1 << ADEN); // Enable ADC
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler to 128
while(1)
{
ADCSRA |= (1 << ADSC); // Start the conversion
while (ADCSRA & (1 << ADSC)); // Wait till the conversion is done
ADCLow = ADCL; // get the ADCL 8 bits
ADCFull = (ADCH<<8 | ADCLow) / 4;
/* 16 bit variable, shift the ADCH to the 9th and 10th position and append the 8 bit ADCL
I divided the 10 bit -> 0-1024 by 4 to get 0-256 which is the range of the RGB led */
for(i=0; i<NUM_LEDS;i++){ // Write to each led the current brightness
led[i].r=0;
led[i].g= ADCFull;
led[i].b=0;
ws2812_setleds(led,NUM_LEDS);
}
}
}
I edited the Make file i found inside the ws2812 library to fit my processor, clock speed and programmer.
F_CPU = 20000000
DEVICE = attiny44
CC = avr-gcc
LIB = light_ws2812
PROJECT = Delta_lights
DEP = ws2812_config.h Light_WS2812/light_ws2812.h
CFLAGS = -g2 -I. -ILight_WS2812 -mmcu=$(DEVICE) -DF_CPU=$(F_CPU)
CFLAGS+= -Os -ffunction-sections -fdata-sections -fpack-struct -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions
CFLAGS+= -Wall -Wno-pointer-to-int-cast
LDFLAGS = -Wl,--relax,--section-start=.text=0,-Map=main.map
hex: $(PROJECT)
$(LIB): $(DEP)
@echo Building Library
@$(CC) $(CFLAGS) -o Objects/$@.o -c Light_WS2812/$@.c
$(PROJECT): $(LIB)
@echo Building $@
@$(CC) $(CFLAGS) -o Objects/$@.o Examples/$@.c Light_WS2812/$^.c
@avr-size Objects/$@.o
@avr-objcopy -j .text -j .data -O ihex Objects/$@.o $@.hex
@avr-objdump -d -S Objects/$@.o >Objects/$@.lss
.PHONY: clean
clean:
rm -f *.hex Objects/*.o Objects/*.lss
program: $(PROJECT).hex
avrdude -p t44 -P usb -c usbtiny -U flash:w:$(PROJECT).hex
After i ran the following commands from the shell:
make -f Makefile clean // clean previous builds
make -f Makefile hex // build the hex file
make -f Makefile program // flash the hex to the board
Video of the result:
As i showed before the arduino bootloader + led code almost filled the attiny44 memory, the C hex instead only seize 900 byte out of 4kb programmable memory ( 25% ).
Arduino high level libraries provide an easy and fast way to achieve the desired result but in some cases, where memory or speed matter, coding directly in C is the way.