Arduino R2R DAC: Timer Interrupts

Up to this point I’ve been handling all of the timing in my Arduino projects using the delay (or delayMicroseconds) function. This has worked pretty well but isn’t without it’s issues. Primarily there are two problems that need to be addressed. First, when using the delay function my timing doesn’t take into account the time it takes to process the rest of the code. And second when using delay my Arduino isn’t able to do anything else. If I wanted to, for instance, run two oscillators simultaneously at different speeds everything would break down.

The solution to these problems is to leverage timer interrupts. This essentially sets up a clock that calls a function at regular intervals. This means my timing will have much higher accuracy and I can have the Arduino do whatever I want in between updates.

Arduino Timers

The Arduino Uno has three timers appropriately named Timer0, Timer1 and Timer2. each of these runs off the 16MHz clock oscillator within the Arduino.

Each timer has a couple important parameters we can control. The first is something known as a prescaler. The prescaler allows us to slow down the clock speed from 16MHz to a more manageable speed. The prescaler values available are 1 (no change), 8 (sets timer to 16MHZ/8 = 2MHz), 64 (slows the timer to 250kHz), 256 (62.5kHz) and 1024 (15.625kHz). These prescaler are set by writing ones different combinations of three registers (CSx0, CSx1 and CSx2) as seen in the following grid.

Clock Selector Bits

Note: the x in these register names should be replaced with the timer number.

The second parameter that will impact our timing is the value in the output compare register (OCR). The timer will count up based on the clock frequency and prescaler. Each time it reaches the value in the OCR register it will reset and send an interrupt. On the Arduino Uno Timers 0 and 2 have an 8 bit counter meaning the OCR can be any value between 1 and 256. Timer 1 is a 16 bit timer meaning it can count as high as 65536.

Math Time

So how do we put this all together? Lets say we want our saw wave to run at 1kHz. The first thing we have to correct for is the steps in the saw itself. Right now we’ve got the saw wave set up to cycle through 16 voltage levels, so right away our 1kHz signal will require the timer to fire at 16Hz. No problem!

So to get the 16MHz clock input down to 16Hz we first need to apply a prescaler. Lets divide the 16MHz by a prescaler of 8 (16MHz/8 = 2MHz). Now to get that 2MHz down to 16kHz we need to set our OCR. if we divide the timer speed by the desired speed we’ll find the value we need (2MHz/16kHz = 125).

Lets Write It

Enough theory, let’s write some code! First things first, I define a function to initiate the timer and call it in the setup function.

void timer1_init();

void setup() {
  DDRB = B1111;      //Set Pins 8-11 as Inputs

  timer1_init();    //Initiate timer
}

For the timer function we want to start by disabling all interrupts and setting the following three registers to zero. This initiates the timer.

  noInterrupts();        

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

Next we set the OCR value.

  OCR1A = 125;                //Compare Value

We set the timer into CTC mode using the following command. CTC mode allows us to trigger our interrupts each time the counter hits the OCR value. This is immediately followed by a command setting the prescaler and a final command enabling the interrupt itself. Last we reenable the interrupts.

  TCCR1B |= (1 << WGM12);       // CTC mode
  TCCR1B |= (1<<CS11);         // 8 prescaler 
  TIMSK1 |= (1 << OCIE1A);    // enable timer compare interrupt

  interrupts();     

So that sets up the interrupt but how does it get called? Essentially what happens is each time the interrupt triggers it calls a specific function known as ISR. We can set up the ISR function as follows.

ISR(TIMER1_COMPA_vect){
  PORTB = v_level;         
  v_level = (v_level + 1) % 16;
}

And there we have it. We’ve done away with the evil delay function and replaced it with a timer interrupt. I’ll finish off with the complete code and I’ll see you all soon.

#define PIN_8 8
#define PIN_9 9
#define PIN_10 10
#define PIN_11 11

#define N 15

int DAC_bus[] = {PIN_8, PIN_9, PIN_10, PIN_11};

int v_level = 0;

void timer1_init();

void draw_saw();

void setup() {
  DDRB = B1111;      //Set Pins 8-11 as Inputs

  timer1_init();    //Initiate timer
}

void loop(){
  }

void timer1_init(){
  noInterrupts();        
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 125;                //Compare Value
  TCCR1B |= (1 << WGM12);      // CTC mode
  TCCR1B |= (1<<CS11);    // 8 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt

  interrupts();     
}

ISR(TIMER1_COMPA_vect){
  PORTB = v_level;         
  v_level = (v_level + 1) % 16;
}

555 Based Piezo Trigger

I’ve always been drawn to drum pads and kits. They are lots of fun and offer a slightly more tactile method of control then rows of pots and switches. So today while I was playing around on my breadboard I was drawn to pull out some piezoelectric disks and start experimenting.  What I’ve come up with is a very simple drum trigger circuit that you can build and experiment with.

This circuit uses a 555 timer set up in monostable mode. A monostable 555 timer will output a square wave pulse whenever it receives a trigger pulse from the piezo disc at pin 2. The pulse output from the 555 can then be adjusted through the 500K ohm pot placed between V+ and pin 7. The output pulse is then sent into the base of a 2N3904 transistor which works as a gate between the audio source and the speaker. This means when the pulse from the 555 is high the audio will pass through the transistor and when the pulse ends and the 555 output goes low the transistor will block the audio from passing.

If you are interested in adjusting the pulse length beyond what is available using the pot this can be achieved by adjusting the electrolytic capacitor between pin 6 and ground. By lowering the value of this cap you can shorten the range of pulse lengths available. Conversely by increasing it you can access a longer range of pulses.

By setting up 4 or 5 of these piezo trigger circuits you could create a fairly versatile set of drum pads. Since the audio source can be switched out or developed further there’s a lot that you can do to expand on the acoustic possibilities of your drum kit. You can try experimenting with different oscillators, Filters, LFOs, White Noise Generators or anything you want.

555 Oscillators in Series

I’ve been spending a lot of time lately playing around with 555 timer chips and wanted to quickly share my latest creation. This project uses four 555 timers each set up as a standard astable oscillator. I’ve then connected the output from pin 3 of each oscillator to the control voltage at pin 5 of the next subsequent chip. Essentially this means each 555 timer is working as an LFO for the next oscillator to it’s right. I also increased the size of the capacitor between pin 6 and ground of the two left-most oscillators in order to  lower their frequency.

I was quite pleased with the range and depth of sounds it produced however, it should be said that I built this as a proof of concept and it is not fully flushed out. I would be very interested to try a similar setup with a different waveform. I feel like this idea would really come into it’s own if used with a triangle or sine wave oscillator which produced a wider range of tones. I have also been experimenting, with some success, with adding capacitors between the output and control voltage inputs to smooth the square wave slightly and create a saw tooth pattern. Without an oscilloscope on hand however this is proving difficult to optimize.

This is also a circuit which can be easily expanded by adding additional oscillators and admittedly there is a little voice screaming in my head to take it to it’s logical conclusion. I expect in my near future I’ll spend a rainy afternoon stringing together as many 555 circuits as I can fit on my breadboards and see what I end up with. I’ll be sure to share the results.