Go Down

Topic: Creating an LFO / Timer question (Read 1 time) previous topic - next topic

yan_g

Feb 18, 2012, 01:53 am Last Edit: Feb 18, 2012, 09:58 pm by yan_g Reason: 1
Hello,

I'm trying to find how to generate an LFO using a PWM output, I searched the web without success though there are innumerable examples, I only found either sketches using delay() which I want to avoid, or stuff way too complicated for my noobish understanding. I chose to post here rather than in the audio forum because it seemed a rather basic coding thing.

I have no idea how to proceed... The method I tried seems to be completely wrong (waiting for a number of milliseconds between each output value in/decrementation, which makes a 511ms duty cycle for a complete sweep up and down through all 256 values when the delay is 1ms).

How should this be done instead? (Besides I want to be able to output more waveforms than stupid triangles or sawteeth)

Any help appreciated!

Thanks!

Magician

Use a timer, basically it almost like you did, only more precision with interrupt driven increment in PWM. You can generate a sine if you feed linearly changing value to sin(2*pi* i/256) function (math.h), or check on a link how it's done with LUT:
http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/

yan_g

Thanks, I searched the web for timer tutorials and found this interesting blog post: http://letsmakerobots.com/node/28278

I loaded that sketch:
Quote
#define ledPin 13

void setup()
{
  pinMode(ledPin, OUTPUT);
 
  // initialize timer1
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}

void loop()
{
  // your program here...
}


I played with OCR1A to change frequency, but I really don't get what this means (among other lines):

Code: [Select]
TCCR1B |= (1 << WGM12);

I know nothing about bitwise operators so I searched again and I found out it's like:

Code: [Select]
TCCR1B = TCCR1B | (1 << WGM12);

Now I'm wondering what "1 << WGM12" means... I think I understand this:
A = 0011 1100
B = A << 2
which makes B = 1111 0000, but in this example A is a series of 0s and 1s and the shifter is a decimal, but it isn't the case in the code line, which is confusing me. Can anyone help me understand that code?

Thanks!

yan_g

Ok I finally understood that WGM12 *is* a decimal and equals 3 (just printed it out via serial), but where does this 3 come from?

Is

Code: [Select]
TCCR1B |= (1 << WGM12);

the same as

Code: [Select]
TCCR1B |= 1000;

?

Magician

Visit Atmel.com and download datasheet for your uCPU (depends on board, for UNO - AtMega328). There is an extract, which show 16! different modes of timer settings. WGM12 is a bit, or position in the register, it's not "3" or number, rather a "switch" in line of 16 others switches, which you could turn on or off. 
Quote
Mode WGM13 WGM12 WGM11 WGM10
           (CTC1) (PWM11) (PWM10)
Timer/Counter Mode of TOP Update of TOV1 Flag
Operation OCR1x at Set on
0 0 0 0 0 Normal 0xFFFF Immediate MAX
1 0 0 0 1 PWM, Phase Correct, 8-bit 0x00FF TOP BOTTOM
2 0 0 1 0 PWM, Phase Correct, 9-bit 0x01FF TOP BOTTOM
3 0 0 1 1 PWM, Phase Correct, 10-bit 0x03FF TOP BOTTOM
4 0 1 0 0 CTC OCR1A Immediate MAX
5 0 1 0 1 Fast PWM, 8-bit 0x00FF BOTTOM TOP
6 0 1 1 0 Fast PWM, 9-bit 0x01FF BOTTOM TOP
7 0 1 1 1 Fast PWM, 10-bit 0x03FF BOTTOM TOP
8 1 0 0 0 PWM, Phase and Frequency ICR1 BOTTOM BOTTOM
          Correct
9 1 0 0 1 PWM, Phase and Frequency OCR1A BOTTOM BOTTOM
          Correct
10 1 0 1 0 PWM, Phase Correct ICR1 TOP BOTTOM
11 1 0 1 1 PWM, Phase Correct OCR1A TOP BOTTOM
12 1 1 0 0 CTC ICR1 Immediate MAX
13 1 1 0 1 (Reserved) - - -
14 1 1 1 0 Fast PWM ICR1 BOTTOM TOP
15 1 1 1 1 Fast PWM OCR1A BOTTOM TOP

yan_g

Where do I learn about all this? I can't read a datasheet, I don't even know what a register is for instance...

Isn't there a way to do it without using a timer?

jfenwick

I found this to be a good tutorial on AVRs:
https://sites.google.com/site/qeewiki/books/avr-guide

Magician

#7
Feb 19, 2012, 08:19 pm Last Edit: Feb 19, 2012, 08:23 pm by Magician Reason: 1
You don't have to study all registers, following basic motto of C++ language "use a library and save a time". In this circumstances, libraries are: http://arduino.cc/en/Reference/Libraries
Or you can copy-paste code linked in reply #1.
What is your spec for LFO, freq. range, stability, distortion?
 

yan_g


I found this to be a good tutorial on AVRs:
https://sites.google.com/site/qeewiki/books/avr-guide

The table of contents looks like my last night's dream come true! Thanks!


You don't have to study all registers, following basic motto of C++ language "use a library and save a time". In this circumstances, libraries are: http://arduino.cc/en/Reference/Libraries
Or you can copy-paste code linked in reply #1.
What is your spec for LFO, freq. range, stability, distortion?

I found this library as I was searching for tutorials about timers: http://arduino.cc/playground/Code/Timer1
I thought I might give it a try.

Actually what I want to do is generate waveforms and send them over MIDI, and beeing able to change the frequency/amplitude with sensors. Ideal frequency range would be 2 to 80Hz (I'm that bad) though I might consider a lower high end (and a higher low end) if the tweaking can't be precise enough. I was thinking about generating CV curves as well, which actually seems simpler but I really want to send them over MIDI.

yan_g

Timers seem a little difficult for me to master quickly so I thought I'd focus on the MIDI communication and sensors, which is essential to my project, and reprogram the AVR later when I learn more about timers, to add the LFO functions.

I need to know one important thing before I start thinking more seriously about the features of my controller: can I use the PWM outputs to dim LEDs if I use timers? If I understood correctly, I can't use pins 9 & 11 when I'm using timer1, am I right?

Thanks!

Go Up