IR Receivers TSOP4838 vs TSOP2138

Be careful not to confuse the two. I learned the hard way that the pinouts of the two models is very different: the VCC and GND pins are the other way around. The data sheet  is pretty clear about this, but I still managed to overlook it.

Quote | Posted on by | Leave a comment

MSGEQ7 Spectrum Analyzer Kit

I have designed two PCBs for the MSQEQ7 based audio spectrum analyzer I described in my previous post. See it in action here:

The boards are stacked on top of each other. The bottom one contains the analyzer, timer, and LED driver. The top board contains the LED bar graph displays. The boards are 80x49mm in size in order to fit in a DP8049 Sick of Beige case from dangerousprototypes.com.

pcb-top

pcb-bottom

pcb-stacked

Design files (eagle), schematic, etc. on github

Posted in audio, avr, pcb | Tagged | Leave a comment

Some notes about AVR timers

Some people asked about how to arrive at the timer settings used in the IR library port. Here’s my quick guide on how to set the timer parameters to have an interrupt service routine called every 50 microseconds.

1. ATtiny4313 / ATtiny2313 (TIMER1, 16 Bit)

Test program:

ISR(TIMER1_OVF_vect)
{
    // we want to arrive here every 50 microseconds
    PORTD ^= _BV(PD5);
}

void setup_timer1(void)
{
    TCCR1A = 0;
    TCCR1B = _BV(CS11);  // prescale /8
    TIMSK |= _BV(TOIE1); // enable overflow interrupt
    sei();               // enable interrupts
}

int main(void)
{
    DDRD = _BV(PD5);
    setup_timer1();
    for (;;) {_delay_ms(500); }
    return 0;
}

The TIMER1 on the attiny4313 is a 16-bit timer. Hence the timer counter register TCNT1 runs from zero to MAX = 2^16 – 1 = 65535. When it reaches the MAX value of 65535 the timer overflow interrupt service (ISR) routine gets called and then the timer will start over counting from zero to MAX. How frequent is the ISR called?

  • We use an external 16 Mhz crystal
  • We set the timer clock prescaler to /8
  • The TCNT1 is incremented 16 000 000 / 8  = 2 000 000 times per second
  • We need 65535 increments to have the timer overflow and the ISR called

65 535 / 2 000 000 = 0.0327675 seconds

The ISR is called every 32.7675 milliseconds. We toggle PD5 in the ISR so let’s check this pin with a logic analyzer:

16bit-1

Now what if we want our ISR to be called every 50 microseconds? We need to adjust the start value to something greater than zero so that we do not need to wait for the full 65535 increments to occur. How many timer increments per microsecond?

  • clock frequency is 16 000 000
  • timer clock prescaler is system clock /8
  • 1 000 000 microseconds per second

16 000 000 / 8 / 1 000 000 = 2 timer increments per microsecond

We can now adjust the initial timer start value to 65535 – 2 * 50 = 65435 and have to do this adjustment every time the timer overflows, too:

ISR(TIMER1_OVF_vect)
{
    PORTD ^= _BV(PD5);
    TCNT1 = 65435U;
}

void setup_timer1(void)
{
    TCCR1A = 0;
    TCCR1B = _BV(CS11);  // prescale /8
    TIMSK |= _BV(TOIE1); // enable overflow interrupt
    TCNT1 = 65435U;      // initial start value
    sei();
}

The timer will now run from 65435 to 65535, i.e. 100 increments and each increment takes 2 microseconds.

Let’s see this in the logic analyzer:

16bit-2

We are almost there. To get closer to 50 microseconds, we need to adjust for the time we spend inside the ISR. We could look at assembly code and check how long every single instruction takes, or we can just guess a “fudge factor” and measure:

#define CLKFUDGE 3

ISR(TIMER1_OVF_vect)
{
    PORTD ^= _BV(PD5);
    TCNT1 = 65435U + CLKFUDGE;
}

16bit-3

That’s close enough. You can increase the precision by reducing the timer prescale value, but you will also reduce the maximum interval in between calls to the ISR if you do so.

2. ATtiny85 (TIMER1, 8 Bit)

What changes?

The main difference is that the atttiny85 has an 8-bit TIMER1. Thus, the counter runs from zero to 255 and then wraps around. The names of some registers change and the attiny85 has two prescaler units; one using the internal system clock and another one for the fast peripheral clock. So be careful and consult the datasheet for the exact bits to set in the timer control register. I also switched from pin PD5 to PB0.

ISR(TIMER1_OVF_vect)
{
    PORTB ^= _BV(PB0);
}

void setup_timer1(void)
{
    TCCR1 = _BV(CS12);   // prescale by using peripheral clock /8
    TIMSK |= _BV(TOIE1); // enable overflow interrupt
    sei();
}

Let’s follow the same steps as before. Without any adjustments we can expect an interrupt every 127.5 microseconds.

  • We use an external 16 Mhz crystal
  • We set the timer clock prescaler to PCK/8
  • The TCNT1 is incremented 16 000 000 / 8  = 2 000 000 times per second
  • We need 255 increments to have the timer overflow and the ISR called

255 / 2 000 000 = 0.0001275 seconds = 127.5 microseconds

and indeed:

attiny85-1

To get to 50 microseconds, we adjust the start value in almost the same way as before. Instead of subtracting from the maximum 16 bit value of 65535 (= 0xFFFF), we use the maximum 8 bit value instead, i.e. 255 (= 0xFF).

16 000 000 / 8 / 1 000 000 = 2 timer increments per microsecond

 255 – 2 * 50 = 155 = new start value

let’s try:

attiny85-2

again, applying a “fudge factor”:

#define CLKFUDGE 3

ISR(TIMER1_OVF_vect)
{
    PORTB ^= _BV(PB0);
    TCNT1 = 155U + CLKFUDGE;
}

void setup_timer1(void)
{
     TCCR1 = _BV(CS12);   // prescale by using peripheral clock /8
     TIMSK |= _BV(TOIE1); // enable overflow interrupt
     TCNT1 = 155U + CLKFUDGE;
     sei();
}

attiny85-3

3. ATmega328p

You can use TIMER1 (16 bit) or TIMER2 (8 bit). Check the datasheet for the exact register names and how to set the prescaler.

Posted in avr, timer | Tagged , , | Leave a comment

How to Generate Gerber Files for Seeed Studio’s Fusion PCB Service

More a note to myself, but you may find this useful, too.

Eagle design rules and cam job files

Fusion PCB Order Submission Guidelines

Next, unzip/runrar and move to eagle:

$ mv SeeedStudio_2layer_DRU_no_angle_20140221.dru SeeedStudio_4layer_DRU_no_angle_20140221.dru \
 /Applications/EAGLE-6.5.0/dru
$ mv Seeed_Gerber_Generater_2-layer.cam \
 /Applications/EAGLE-6.5.0/cam

Run Eagle design rule check

open File / CAM Processor …
open File / Open / Job …

Links

http://dangerousprototypes.com/2011/10/26/a-guide-to-seeedstudio%E2%80%99s-fusion-pcb-service/

http://www.lucadentella.it/en/2011/10/22/guida-al-servizio-fusion-pcb-di-seeedstudio/

BTW, Seeed Studio’s Fusion PCB Service is pretty awesome. I once submitted gerber files where it wasn’t clear whether to do slots or drill holes for a 2.1mm power jack. I was promptly contacted and asked how it should be done. This is service I did not expect at this price. Thank you Seeed Studio!

CatchC3E4

Posted in eagle, pcb | Leave a comment

3.5mm audio jack breakout board

None of the 3.5mm audio jacks I know of fit on a standard breadboard. For my previous project I made a breakout board for the “Lumberg KLBR4” audio jack to address this. You can buy those jacks for example at Reichelt.

klbr4-board

klbr4-naked-on-breadboard

klbr4-on-breadboardEagle files: https://github.com/alohr/klbr4breakout

Posted in breakout | Leave a comment

MSGEQ7 based Audio Spectrum Analyzer w/ LM3915, attiny2313

Here’s how I built an audio frequency spectrum display around the MSEQ7 spectrum analyzer – in stereo:

I took a lot of inspiration from this:

… and built it first with an Arduino and Sparkfun’s spectrum shield. Later I replaced this combo with an attiny2313 and two bare MSGEQ7s.

The original uploader planeboy21 did not link to any description or schematic, but gave a few hints in the comments. From this I figured a few things.

First, the analog output of the MSGEQ7 is directly connected to the signal input of a single LM3915 which drives all 10 LED bar graph displays. The analog signal is multiplexed over the seven bands. In other words, while we cycle through the frequency bands, we provide power to only one of the bar graphs at a time.

The Arduino’s job is to orchestrate the whole thing, send the reset and strobe signals to MSGEQ7, and to multiplex the bar graph displays. The Arduino never does an analog to digital conversion of the MSGEQ7 signal. This is important. It allows me to replace the Arduino with an attiny2313 which lacks lacks ADC, but has more than enough IO pins for this project.

MSEQ7 timing

There is a pretty good article MSGEQ7-Based DIY Audio Spectrum Analyzer: Construction at eetimes.com. This is where I got this timing diagram from:

timing-diagram

We can read the MSEQ7’s signal at the times shown in green. The output of the MSGEQ7 is connected to the input of the LM3915 which controls one 10-LED bar graph display at a time. There are 7 bar graphs – one for each frequency band. While cycling through the bands, we have to switch on the respective bar graph.

Source code is at github.

Schematic

This is for a single audio channel. For stereo I simply duplicated the MSGEQ7 + LM3915 section. The CAT1 .. CAT10 go the the cathodes of the bar graphs, the AN1 .. AN7 to the anodes. The LEDs are switched by P-channel MOSFETs.

msgeq7-simple

The two resistors R13 and R14 around the LM3915 control the brightness. I picked resistor values which will give a pretty high current of 28mA for the LEDs. This is on purpose, because each bar graph is “on” only 1/7th of the time.

Posted in audio, avr | Tagged , , | 16 Comments

An AVR and photoresistor controlled LEGO Lighthouse

Our local DIY and hardware store gave away some tiny LEGO freebies a while ago. The little lighthouse I chose absolutely had to have an LED in inside its lantern room. Making LEDs blink is simple enough. To make it a little more interesting than the simple “hello world” of programming microcontrollers, it turns itself automatically on and off depending on the light conditions.

DSC 2102

How does it work?

The photoresistor — or light-dependent resistors (LDR) — is connected to an analog input pin AIN1 as part of a voltage divider. A potentiometer, essentially an adjustable voltage divider, is connected to the analog pin AIN0. The darker it gets, the higher the resistance of the LDR, and hence the lower the voltage on the analog pin AIN1.

lighthouse-a

The analog comparator compares the two voltages on the analog pins 0 and 1. If the voltage on AIN0 is higher than on pin AIN1, then AIN1, the analog comparator output bit ACO of the ACSR register is set. Here is how to turn on an LED on pin PB4 depending on the level of light detected:

#include <avr/io.h>

int main(void)
{
    DDRB |= _BV(PB4);
    for (;;) {
        int on = ACSR & _BV(ACO);

        if (on)
            PORTB |= _BV(PB4);
        else
            PORTB &= ~(_BV(PB4));
    }
}

Sleep mode (because battery life)

The problem now is that the battery would not last very long. The ATtiny needs power and there is also current flowing through the LDR and the potentiometer. The amount of this current depends on the intensity of the ambient light and how the trimmer potentiometer is set.

First, sleep mode. Some useful links: AVR and Arduino sleep mode basics, Nick Gammon’s excellent Power saving techniques for microprocessors has lots of code examples, and Sparkfun’s H2OhNo! low-power ATtiny project also uses an ATtiny85.

The main loop with sleep mode instead of a simple delay for the blinking light would look like this:

    for (;;) {
        int blink = ACSR & _BV(ACO);

        if (blink) {
            PORTB |= _BV(PB4);
	    _delay_ms(BLINK_DELAY);
            PORTB &= ~(_BV(PB4));
            watchdog_enable(WD_2_SECONDS); // sleep for 2 seconds
        } else {
            watchdog_enable(WD_8_SECONDS); // sleep for 8 seconds
	}
	powerdown();
	watchdog_disable();
    }

If it is dark enough, PB4 will be set to high to turn the LED on. It will stay on for some time (800ms in my case) and when the time is up, the microcontroller is powered down. The watchdog timer will wake it up 2 seconds later. If there is enough light though, the microcontroller is powered down for 8 seconds.

The second problem is the continuous current flowing through the two voltage dividers. This current flows irrespective of the microcontroller being powered down or not. To stop this, I added the switching transistor controlled by port PB3. I got the current consumption during sleep down to 5 microamps. This is very much in line with the Sparkfun project. According to the datasheet I can expect something around 4 microamps. Close enough.

Powerdown supply current

This leaves the LED as the main power consumer. I power my circuit using two N cell batteries. They look like a nice trade off between size and capacity. My prototype of the circuit ran on one set of batteries 24/7 from March 2013 until February 2014.

DSC 2089

Overkill?

Perhaps a microcontroller is complete overkill for a small toy like this, but I just don’t know enough about electronics to design a circuit that would do the same without using a microcontroller. Any ideas how to do this would be welcome.

Resources

Schematics and code are on github: https://github.com/alohr/avr-lighthouse

Posted in attiny85, avr, low-power, sleep-mode | Tagged , , , | Leave a comment