OCR1AL/OCR1BL confusion. Where is the output?

Hello,

I am confused about writing fast pwm values via timer1 on an Arduino Uno.

I'm using ISRs to generate audio outputs on two pwm pins by writing 8bit values to OCR1AL and OCR1BL.
I'm using timer1 in high speed 8 bit mode.
I assumed that OCR1AL and OCR1AH values are written to pin9 and OCR1BL and OCR1BH to pin10. Is this correct?

If not, is it at all possible to control two pins with timer1 with the high speed 8 bit mode?

Thanks!
Marko

I assumed that OCR1AL and OCR1AH values are written to pin9 and OCR1BL and OCR1BH to pin10. Is this correct?

No. Perhaps you mean which pins are set/reset by the timer during operation. They are labeled OC1A (Arduino pin 9) and OC1B (Arduino pin 10).

Thank you, this is what I meant – vaguely at least :wink:

I'll try to describe my assumption more precisely (all referring to an Arduino Uno):

If I set for example OCR1AL = 127, this will cause timer1 to output a High value on Arduino Pin 9 during the first half if its cycle, and a low value during the second half of its cycle.
If I set OCR1BL = 127, the same thing will happen on Arduino Pin 10.

Is this correct?

Thanks!

The action depends on how you have set the timer control registers, which you did not clearly state. See the data sheet for details.
Or, try it and see.

Thanks.
Here are my settings for timer 1

  DDRB = 6;  // Make timer's PWM 9 and 10 pin an output
  TCCR1B  = (1 << CS10);    // Set prescaler to full speed 16MHz (no prescaling)
  TCCR1A = (1 << COM1A1); 
  TCCR1A |= (1 << COM1A0);  
  TCCR1A |= (1 << WGM10);   // Put timer into 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12);

The reason why I'm asking all of this is because I'm trying to generate two audio outputs with different frequencies on the Arduino pins 9 and 10. Pin9 is working fine, pin 10 isn't.
The values of pin 9 are set by an ISR running on timer2. The values of pin 10 are set by an ISR running on timer0. The former is writing the resulting values to OCR1AL, the latter to OCR1BL.

Here are the setup settings:

  TCCR2A = 0;               // We need no options in control register A
  TCCR2B = (1 << CS20);     // no prescalar
  TIMSK2 = (1 << OCIE2A);   // Set timer to call ISR when TCNT2 = OCRA2

  TCCR0A = 0;               // same for timer0
  TCCR0B = (1 << CS20);     
  TIMSK0 = (1 << OCIE0A);

The ISRs look as follows:

ISR(TIMER2_COMPA_vect) {  // Called each time TCNT2 == OCR2A
  static byte index = 0;    // Points to successive entries in the wavetable
  OCR1AL = wave[index++]; // Update the PWM 9 output, working fine
  asm("NOP;NOP");         // Fine tuning
  TCNT2 = 5; // Timing to compensate for time spent in ISR
}

ISR(TIMER0_COMPA_vect) {  // Called each time TCNT2 == OCR2B
  static byte index = 0;    // Points to successive entries in the wavetable
  OCR1BL = wave[index++]; // Update the PWM 10 output. Not working!
  asm("NOP;NOP");         // Fine tuning
  TCNT0 = 5;              // Timing to compensate for time spent in ISR
}

I assume that something in the control registers of timer1 is wrong, but I can't figure out what it is...

Here's the complete code, in case this looks more transparent:

/******** Load AVR timer interrupt macros ********/
#include <avr/interrupt.h>

/******** Sine wave parameters ********/
#define PI2     6.283185 // 2 * PI - saves calculating it later
#define AMP     127      // Multiplication factor for the sine wave
#define OFFSET  128      // Offset shifts wave to just positive values

/******** Lookup table ********/
#define LENGTH  256  // The length of the waveform lookup table
byte wave[LENGTH];   // Storage for the waveform

void setup() {
  /******** Populate the waveform lookup table with a sine wave ********/
  for (int i=0; i<LENGTH; i++) {
    float v = (AMP*sin((PI2/LENGTH)*i));  // Calculate current entry
    wave[i] = int(v+OFFSET);              // Store value as integer
  }
 
  /******** Set timer1 for 8-bit fast PWM output ********/
  DDRB = 6;// pinMode(9, OUTPUT) and pinMode(10, OUTPUT); // Make timer's PWM pin an output
  DDRD = 255;
  TCCR1B  = (1 << CS10);    // Set prescaler to full speed 16MHz (no prescaling)
  TCCR1A = (1 << COM1A1);  // PWM pin to go low when TCNT1= OCR1A
  TCCR1A |= (1 << COM1A0); 
  TCCR1A |= (1 << WGM10);   // Put timer into 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12); 

  /******** Set up timer 2 to call ISR ********/
  TCCR2A = 0;               // We need no options in control register A
  TCCR2B = (1 << CS20);     // Set prescaller to divide by 8 // try TCCR2B = (1 << CS20) for finer range
  TIMSK2 = (1 << OCIE2A);   // Set timer to call ISR when TCNT2 = OCRA2
//  TIMSK2 |= (0 << OCIE2B); // doesn't work, if TCCR1A |= (1 << COM1B1) is not set

  /******** Set up timer 0 to call ISR ********/
  TCCR0A = 0;               // We need no options in control register A
  TCCR0B = (1 << CS20);     // Set prescaller to divide by 8 // try TCCR2B = (1 << CS20) for finer range
  TIMSK0 = (1 << OCIE0A);   // Set timer to call ISR when TCNT0 = OCRA2
    
  OCR2A = 60;               // sets the frequency of the generated wave has to be > TCNT2
  OCR0A = 80;
  sei();                    // Enable interrupts to generate waveform!
}

void loop() { 
}

/******** Called every time TCNT2 = OCR2A ********/
ISR(TIMER2_COMPA_vect) {  // Called each time TCNT2 == OCR2A
  static byte index = 0;    // Points to successive entries in the wavetable
  OCR1AL = wave[index++]; // Update the PWM output
  asm("NOP;NOP");         // Fine tuning
  TCNT2 = 5; // Timing to compensate for time spent in ISR
}
/******** Called every time TCNT2 = OCR2B ********/
ISR(TIMER0_COMPA_vect) {  // Called each time TCNT2 == OCR2B
  static byte index = 0;    // Points to successive entries in the wavetable
  OCR1BL = wave[index++]; // Update the PWM output
  asm("NOP;NOP");         // Fine tuning
  TCNT0 = 5;              // Timing to compensate for time spent in ISR
}

Unless there is some compelling reason to do so, you should not be using ISRs.

The timer can, and is intended to, control pins 9 and 10 directly.

Thank you jremington,

the reason why I'm using ISRs is that I wasn't able to generate clean audio by using the loop function. I suspect that its timing is not accurate enough and I thought that using the timers in combination with ISRs would yield much more precise timing.
So far, I was indeed able to generate remarkably clean audio signals on pin9.

Anyway, I still don't understand why I can't get pin10 to work.

Can you tell, if my register values for timer1 are correct for what I intend to do?

TCCR1B  = (1 << CS10);    // Set prescaler to full speed 16MHz (no prescaling)
  TCCR1A = (1 << COM1A1);
  TCCR1A |= (1 << COM1A0);  
  TCCR1A |= (1 << WGM10);   // Put timer into 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12);

Thanks a lot for your help!!
Marko

The timers WILL generate much more precise timing, when used directly on the output pins, than any ISR approach.

It is just plain silly to think you can improve on the hardware, using software. Again, you should not be using ISRs.

For the record, though, your code is extremely confusing. I can't imagine why you would be writing to Timer1 control registers when you claim to be using Timer0 and Timer2.

The values of pin 9 are set by an ISR running on timer2. The values of pin 10 are set by an ISR running on timer0. The former is writing the resulting values to OCR1AL, the latter to OCR1BL.

Edit: OK, now I understand what you are trying to do, but there are certainly better approaches.
You have not set Timer1 COM1B1:0 appropriately, so pin 10 is not being changed by the timer.

A major problem with ISRs in timing is the latency. My approach would be to turn off ALL interrupts, and just use a loop. Look up Direct Digital Synthesis.

Thanks for your advice jremington.

However, I would still like to understand why the example I posted doesn't work. I would expect the Pin 10 to react to the values that are written to OCR1BL which is not happening.

Are the configurations of timer1 correct? I suspect that this is where it's going wrong.
Here are those lines again.

TCCR1B  = (1 << CS10);    // Set prescaler to full speed 16MHz (no prescaling)
  TCCR1A = (1 << COM1A1);
  TCCR1A |= (1 << COM1A0); 
  TCCR1A |= (1 << WGM10);   // Put timer into 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12);

Thanks!

As I stated in reply #7, Timer1 is not programmed correctly.

You have not set Timer1 COM1B1:0 appropriately, so pin 10 is not being changed by the timer.

As @jremington says, you have not set up Timer1 correctly for output on both pins.

I do not think that using Timer2 and Timer0 to change the values of OCR1A and OCR1B is necessary or working the way you think it is.

You are running all timers at the same clock rate with no prescaler. At OCR2A = 60 and OCR0A = 80 you change the values of OCR1A and OCR1B to the next value in your wave matrix.

But, Timer 1 is running in mode 5 -- 8 bit fast pwm to 255. In that mode, the update of OCR1X is at BOTTOM. That is, Timer 1 will run up to 255, reset itself to 0 and change the compare match values when it does so.

I think that it would be much simpler and without multi-timer ISR timing issues to just use an overflow interrupt on Timer1 to change the values of OCR1A and OCR1B.

@jremington: thank you very much. For some reason at first my browser only showed the first two lines of your reply #7 before I sent my last reply. Therefore I didn't see your comment regarding COM1B1 until now. I'll try that first thing tomorrow.

@cattledog: thanks for the advice. I'll try to do it the way you suggest, but first I'll try to get this example working.

Unfortunately I still didn't get it to work properly.
If I set

TCCR1A |= (0 << COM1B1);

I get no output on pin10.

If I set

TCCR1A |= (1 << COM1B1);

I get the same pitch on pin 9 as on pin 10, although I'm setting OCR0A and OCR2A to different values.

Any help would be much appreciated! Thanks!!

TCCR1A |= (1 << COM1B1);

That is correct for setting output on pin D10.

I get the same pitch on pin 9 as on pin 10, although I'm setting OCR0A and OCR2A to different values.

The output duty cycle is determined by OCR1A and OCR1B which are both set to wave[index++] in the respective timer0 and timer2 ISRs. I would expect them to be the same.

With no prescaler and 8 bit pwm, the frequency of the pwm is 62,500 Hz.

How does the duty cycle relate to "pitch".

Thank you cattledog,

the ISRs are resetting TCNT0 and TCNT2 respectively to a low value. Therefore I would expect the duty cycle of the timers 0 and 2 to be independent of each other – according to the value of OCR0A and OCR2A –, as they are stepping through the wave array at different speeds.

I would expect the resulting frequenzy to be 16MHz/(256 * OCR0A) for timer0 and 16MHz/(256 * OCR2A) for timer2.

I don't really understand why they tune in to the same frequency while OCR0A and OCR2A are set to different values.
Do you see my mistake?

Thanks!
Marko

The duty cycle has nothing to do with the frequency.

Why not tell us what you are actually trying to do?

I'm trying to create two sine tone oscillators that can be tuned independently of each other. One oscillator should be output through pin9, the other through pin10. I'm using a 10kOhm resistor and 0.1 microF capacitor as a lowpass filter per output, in order to average the PW modulation.

Right now I have output on both pins, but the resulting frequency is always the same.

It should be adjustable by assigning values to OCR2A and OCR0A. If is set OCR2A and OCR0A close to each other (e.g. OCR2A = 50 and OCR0A = 60) I get the exact same frequency on both pins. If I tune them further apart (e.g. OCR2A = 40 and OCR0A = 100) they lock into an octave interval. When I slightly change any of those values, both frequencies change but they always remain in unison or in an octace interval.

the ISRs are resetting TCNT0 and TCNT2 respectively to a low value. Therefore I would expect the duty cycle of the timers 0 and 2 to be independent of each other - according to the value of OCR0A and OCR2A -, as they are stepping through the wave array at different speeds.

Yes, I see that now.

I still think that there is an issue with the updating of Timer1 in 8 bit fast pwm mode. OCR1X will update only when the cycle completes.

All timers are set to the same prescaler, and I think that if, for example, OCR2A is set at 50 and the ISR will update the value of OCR1A 5 times along Timer1's run up to 255, only the last value will be valid for the update.

I think that you can do what you are trying to do if Timer0 and Timer2 which are telling Timer1 when to change are running slower than Timer1.

For example if Timer 2 changes OCR1A every cycle of Timer 1 and Timer 0 changes OCR1B every two cycles of Timer 1, then the frequencies will be 2/1. You just can't be faster than the fundamental frequency of Timer 1.

Your original code had Timer2 and Timer 0 with a prescaler of 8. Why did you change to no prescaler?

I don't think the two outputs can be at a ratio something other than an integral divider of the fundamental frequency i.e. 1/2, 1/3, 1/4 of the 62,000 HZ.

There may be other ways of setting up the timers for more flexibility. For example, if you set Timer 1 to Fast PWM with ICR1 as TOP in mode 14 you will have more control over the fundamental frequency then when you are using 8bit with 255 TOP. Still, I think you are going to be limited in the two outputs, by updates every n cycles with >=1.

Dear Cattledog,
your explanation makes a lot of sense. Thank you very much. Now I understand better what the problem is. I'll try the mode 14 solution with ICR1 you suggested.