Understanding Output

382 views
Skip to first unread message

telb...@googlemail.com

unread,
Aug 26, 2009, 6:45:47 PM8/26/09
to Auduino
Hi Everyone,

Firstly I'd like to thank Peter Knight for a cracking project - and
for opening it up as open source. It's obviously a lot of work to put
something like this together, so thanks for sharing.

I'm trying to make sense of the code at the moment - I tried to add a
second output to get a second "copy" of the output on another pin, but
I couldn't make sense of the code.

I changed this part:

// Changing these will also requires rewriting audioOn()
#define PWM_PIN 3
#define PWM_PINTWO 9 <---------- **here**
#define PWM_VALUE OCR2B
#define LED_PIN 13
#define LED_PORT PORTB
#define LED_BIT 5
#define PWM_INTERRUPT TIMER2_OVF_vect

Edited here:

void setup() {
pinMode(PWM_PIN,OUTPUT);
pinMode(PWM_PINTWO,OUTPUT); <---------- **here**
audioOn();
pinMode(LED_PIN,OUTPUT);
}

And then looked here:

void audioOn() {
// Set up PWM to 31.25kHz, phase accurate
TCCR2A = _BV(COM2B1) | _BV(WGM20);
TCCR2B = _BV(CS20);
TIMSK2 = _BV(TOIE2);
}

And at that point my brain melted. Any chance anyone can explain
what's going on in audioOn() ?

Many thanks,

Tel.

Peter Knight

unread,
Aug 26, 2009, 8:18:47 PM8/26/09
to Auduino
Thanks for your kind words.

On Aug 26, 11:45 pm, "telbo...@googlemail.com"
<telbo...@googlemail.com> wrote:
> And at that point my brain melted.  Any chance anyone can explain
> what's going on in audioOn() ?

Sure. There is a lot to understand here though. First, you'll need the
data sheet for the processor in the Arduino. I'm assuming you're using
a 328 Arduino, so here's the current data sheet.
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf

Read chapter 17. You should recognise some of the names, particularly
when you get to 17.11.

_BV() is a bit vector. _BV(0) is bit 0, so has value '1' (00000001 in
binary). _BV(1) = 2 = 00000010 bin, _BV(2) = 4 = 00000100 bin etc. _BV
(n) has a '1' in the n-th bit.

So taking those lines one at a time:


TCCR2A = _BV(COM2B1) | _BV(WGM20);

This sets up the TCCR2A register. The '|' is a logic OR, so the value
being loaded into it has a '1' in the COM2B1 and WGM20 position, '0'
elsewhere. Therefore, it sets Timer/Counter 2 Control Register A to
the following:

WGM22/21/20 = 0/0/1: PWM, Phase Correct mode (WGM2 will be zeroed in
the line below)
COM2A1/COM2A0 = 0/0 : Normal port operation, OC2A disconnected.
COM2B1/COM2B0 = 1/0 : Clear OC2B on Compare Match when up-counting.
Set OC2B on Compare Match when down-counting.


TCCR2B = _BV(CS20);

Set Timer/Counter 2 Control Register B to the following:
FOC2A/2B: Not set.
WGM22 = 0: Sets PWM mode - see above.
CS22/21/20 = 0/0/1: Set timer clock source to clkT2S which is 16MHz on
most Arduinos. (See Arduino board schematic and data sheet chapter 8)


TIMSK2 = _BV(TOIE2);

Enable interrupt on Timer/Counter2 Overflow. (See Chapter 11 and the
AVR-GCC manual).


So what this does is get Timer2 to count 16 million times per second.
It counts up 0 to 255, then down 255 to 0. (Atmel calls this 'Phase
Correct PWM'). When OCR2B (Auduino calls this 'PWM_VALUE') is more
than the count, the OC2B is high. Otherwise it is low. The OC2B is
connected to pin 5 of the microprocessor, which maps to Arduino pin 3.
(Check data sheet section 1, and the Arduino board schematic).

Therefore, it sets up pin 3 to be a PWM, like analogWrite() - but with
two additional features.
1) An interrupt occurs every cycle. That calls the synthesis maths
routine in the background.
2) The PWM runs much faster than it normally would. The Arduino PWMs
normally run at about 500 or 1000Hz, but Auduino runs them at 31250Hz.
It needs to run them this fast to generate audio waveforms. The PWM
process generates a buzz, but at 31kHz that buzz is past the hearing
range of the human ear (which works up to about 17kHz).


Now if you want to generate a second output, you'll need to do the
following.

1) Because everything is tied to Timer2, by far the easiest solution
is to use the second comparator output for that timer, OC2A. That pin
outputs to Arduino digital pin 11, so now you know why it's labelled
'PWM' on the PCB. You'll need to configure that pin as an output, like
pin 3.
2) Now you need to adjust the setting of TCCR2A to enable PWM mode on
OC2A.
3) You need to adjust the interrupt routine to both OCR2A and OCR2B
are updated with new values every sample.


I know - your head has probably exploded at that point! But persist.
There is a lot to understand, but once you do, you will understand a
lot more how Arduino works internally, and you will have many extra
tools in your programming tool chest. Generating music, speech, TV
signals, data protocols and more are all possible once you've mastered
the data sheet.

Good luck!


Peter

Tel Bonic

unread,
Aug 27, 2009, 5:36:14 PM8/27/09
to Auduino
> I know - your head has probably exploded at that point! But persist.
> There is a lot to understand, but once you do, you will understand a
> lot more how Arduino works internally, and you will have many extra
> tools in your programming tool chest. Generating music, speech, TV
> signals, data protocols and more are all possible once you've mastered
> the data sheet.

Thanks for taking the time to reply - I've downloaded the datasheet
and am currently waiting for the printer to munch through it - I will
indeed have a good read and then chew over your post. I realise I can
just plug both sides of a sterio amp/mixer/doodad into pin3 to get a
second "copy" but where's the fun in that when I can go the long way
round and hopefully learn something along the way? :D I'm already
wondering if perhaps I can play with the phase of the 2nd output to
get something interesting. I'd best get reading ;)
Reply all
Reply to author
Forward
0 new messages