Fab Academy 2019

Progress Documentation - Christian Schmidt

Output Devices

Act on your surroundings

For this weeks assignment, I want to use a RGB LED as an indicator for orientation. The RGB colorspace can be arranged in a cube (or a sphere) so that each 3D direction corresponds to a color. The LED should light up in the color that corresponds to the direction in which it is pointing. To make the LED light up in different colors, I will use pulse width modulation (PWM).

I used the following things to make this board:

  • ATTiny44
  • RGB LED
  • Resistors for the LED (680, 560, 500 Ω for red, green, and blue respectively)
  • 10kΩ pull up resistor
  • 100nF bypass capacitor
  • 2 0Ω resistors
  • 8 MHz Crystal + two 18pF capacitors
  • 3 transistors (I only had BJTs available, which worked fine, but you probably want MOSFETs for quick on/off switching)
  • 3 4.7kΩ resistors to limit current to the transistors base (not in the first design; see below why they are needed)
  • 5mm SMD button (useful for debugging)
  • 1x2 pin jumper (actually not needed if you use the 4.7kΩ resistors)
  • 1x6 pin through hole header for ISP
  • MPU 9250 breakout board
  • headers to connect this board to the breakout board
  • the usual machinery: PCB mill, laser cutter, solder paste, soldering iron

Board Layout

The board layout is dense, with the LED in the center of the board. I added a pin header to program the board and one to connect to a breakout board with the MPU9250, a 9-axis accelerometer, gyroscope, and magnetometer. The MPU is connected via I2C to the ATTiny, which has the benefit over SPI that it needs only two wires, and the area around the ATTiny was already packed with signals.

The first design did not have resistors to isolate the transistors from the programming lines. It turns out that this prevents programming of the board, since the stray capacitance of the transistors obstructs the signals sent and received by the programmer. It took me a while to figure this out.


In the second design iteration, I added resistors between the programming lines and application circuitry, and as an additional safety measure I added a jumper that can be used to separate programming line from the rest of the board.


I tried to program the board with and without the jumper; it worked in both cases, so the jumper is probably unnecessary when the 4.7kΩ resistors are used. However, adding the jumper makes sure the board is programmable in all cases, even at very high frequencies.

Another thing I've noticed is that the new footprint of the RGB LED in the Fab Academies EAGLE library has two pins swapped compared to the old footprint and the LED that I used. That led to a substantial amount of confusion on my side.

Firmware

The ATTiny44 has two timer/counter modules, and four output compare units, which can be used to generate PWM signals on four of its pins. Using the output compare units makes it very easy to generate PWM signals.

First, I set up both of the timer/counter systems. I choose the fast PWM mode, in which the counter always increases; the output pins are set to logical 0 at the smallest value, and to logical 1 when the counter matches the respective output compare register. The output compare registers are initialized with 0xFF, which is the highest value; according to the data sheet, this is an edge case which sets the output pin to logical one at the smallest value (instead of the largest). This means all colors of the LED are initially always on, which makes the LED shine bright white.

// Stop timer during configuration
GTCCR |= (1 << TSM);

// Fast PWM, Clear OCOA/OCOB on BOTTOM, set at match
TCCR0A |= (1 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (0 << COM0B0) | (1 << WGM01) | (1 << WGM00);
// Fast PWM, clock source is I/O clock/256
TCCR0B |= (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);

// Always on
OCR0A = 0xFF;
OCR0B = 0xFF;

// same configuration as timer0
TCCR1A |= (1 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (0 << WGM11) | (1 << WGM10);
TCCR1B |= (0 << WGM13) | (1 << WGM11) | (0 << CS12) | (1 << CS11) | (0 << CS10);

OCR1AL = 0xFF;
OCR1BL = 0xFF;

// start timer
GTCCR &= ~(1 << TSM);

Now, to make the PWM affect the output pins, they have to be declared as output pins.

// Enable pull-up resistor after tristate (see datasheet)
PORTB |= PIN_BLUE;
PORTA |= (PIN_RED | PIN_GREEN);
// configure as output
DDRB |= PIN_BLUE;
DDRA |= (PIN_RED | PIN_GREEN);

The color of the led is now determined by the values of the three registers OCR1B, OCR0B, and OCR0A. The values in these registers control the intensity of the red, green, and blue LED, respectively. Note that OCR1B is a 16 bit register, because timer1 is a 16 bit timer; but since timer0 only has 8 bit precision, I use only 8 bits of timer1. Thus, the value for the red LED has to be written into the lower 8 bits, OCR1BL, while the upper 8 bits, OCR1BH have to be set to zero.

The software is built with a simple Makefile.


Downloads