Pages: [1]   Go Down
Author Topic: Creating an LFO / Timer question  (Read 979 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
« Last Edit: February 18, 2012, 03:58:41 pm by yan_g » Logged

Montreal
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2602
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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/
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
TCCR1B |= (1 << WGM12);

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

Code:
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!
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
TCCR1B |= (1 << WGM12);

the same as

Code:
TCCR1B |= 1000;

?
Logged

Montreal
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2602
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Montreal
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2602
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
  
« Last Edit: February 19, 2012, 02:23:56 pm by Magician » Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

Pages: [1]   Go Up
Jump to: