PWM interrupts

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks,
What interrupts are generated when OCR value is reached in fast mode PWM? I am trying to use fast mode PWM and during the ON time (which is decided by OCR value), I want to activate a relay and deactivate it in the OFF time (from OCR to ICR or TOP value)
Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Remember that for what you described, you don't need any interrupts--you can have the AVR drive the output pin "OCnx" directly.

Remember that if it is a "real" relay you are talking about, the lifetime is quite limited with PWM operation. A typical value might be 100000 operations, so at 10 operations per second the lifetime is 10000 seconds or about 3 hours.

Remember that "real" relays take some milliseconds to turn on/off, and the on/off times may not be symmetrical.

What does the Modes of Operation table for your AVR model and selected timer say? What does the timing diagram for that mode indicate?

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr wrote:
Hi Freaks,
What interrupts are generated when OCR value is reached in fast mode PWM? I am trying to use fast mode PWM and during the ON time (which is decided by OCR value), I want to activate a relay and deactivate it in the OFF time (from OCR to ICR or TOP value)
Thanks.

It sounds like you might be trying to synchronize events rather than turn on/off according to the pwm state. Is that right? I doubt you are trying to turn a relay on/off at a fast PWM rate. If so, you won't get the desired result.

If you are trying to sych. events and If one of the events is to open/close relay contacts, then you will have some delay/latency issues (as another post already pointed out). The activate/deactivate time of a relay is quite unpredictable. It can even be load current dependent (if the load current is AC especially).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't think about the relay contacts. Thanks for that.I agree relays is a bad idea to try out this concept.
What I am trying to create is digital modulation. I am planning to use Timer 0 as the carrier wave and Timer 1 (PWM mode) as the pulse/gate. During the ON time of the pulse, Timer 0 should output the carrier wave and nothing during OFF time. My idea is to use the OCR interrupt to reset timer 0 and then start timer0 when timer1 starts again, in other words gate the timer 0 output with the PCM output. The reason I am using PWM is I want to have control over the ON time of my binary modulated signal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Anybody?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well to do what you require one method would be to configure T1 to do both a compare and an overflow interrupt. In one ISR you set the CS0n bits that start T0 and in the other you reset the bits to stop the timer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, Cliff. Sorry about the cross post. I had another idea and didn't want to confuse it with this one.

Anyway I will try with two timers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Of course I agree it is much cheaper and better to do it in software if you can, but the problems with your relay idea wouldn't be an issue if you just used a transistor instead.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I am doing this one small step at a time. Firstly, I tried to produce a 1kHz signal with timer 1. Here is my code:

void timer_init()

   {

     TIMSK1 |= (1 << OCIE1A); //enable channel 1A interrupt

     sei(); //enable global interrupts


     TCCR1B |= (0 << CS12) | (1 << CS11) | ( 1 << CS10); //start timer at Fcpu/64


     TCCR1B |= (1 << WGM12);//set up for CTC mode
 

     OCR1A = 125; //Value that the micro will compare with current count

   }


ISR(TIMER1_COMPA_vect)


   {  

      PORTB ^= (1 << PB0);

   }

I am using a 8MHz crystal and 64 prescalar. So I get OCR1A value of (8M/64/1000)= 125.

I don't have a scope but will this give me a 1kHz square wave on PortB pin 0 of duty cycle 50%?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks mostly ok, but i think you'll find it's a square wave of 500kHz, since you are toggling at 1000kHz, you need an on AND an off to make one full wave. so i think you'll need a prescaler of 32

Other then that, I'm far from an expert but I think flapping a port like this will be very very inefficient, what you want to do is read your datasheet section on "compare output mode" in pwm mode. You can toggle pins in hardware to generate a pwm signal without using ISR.

EDIT: Sorry i see now your toggling is just a test, you aren't actually trying to generate a pwm on the pin:) to start or stop a timer you set its CSx2:0 bits to 0, then to start it put it back to what the prescaler is, so i suppose in your ISR you might try something like

if (flag == 1)
{
//start timer 0 with no prescaler 
TCCR0B |= ( 1 << CS00) 
flag = 0;
}

if (flag == 0)
{
TCCR1B |= 0; //stop timer 0
flag = 1;
}

make sure you declare flag as volatile.

i don't know, it still seems clunky to me, i wonder if there is a better way to do this, maybe a transistor modulating your signal from a pin toggled in hardware would be better after all... hmm.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, vespine. I was thinking along the same lines. However, I still need to send this modulated waveform to some output pin right? Also I tried 32 and it did not work. (I have a speaker handy which has a 1 kHz resonant frequency so I am using that as a scope) I have tested it with another program and I know it has a loud tone at 1 kHz.

Looks like I may have to use PWM. Will keep trying with timers but PWM may be easier.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hang on, i'm getting confused with what you are calling the "carrier wave" or modulated waveform etc. In your second post you say timer 0 is your carrier wave and timer 1 is your "gate", i think your definition of those 2 terms is actually the same thing, it's the carrier wave that does the modulating, it's the signal which is modulated, and that's what you want to see at the pin, i imagine.

I thought you were setting up timer 1 as the wave which will perform the modulating, which doesn't need to go to the pin, provided you can get it all to work in software.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr,

Is it possible to make a little sketch of exactly the kind of waveform you are hoping to finally achieve (perhaps with some temporal dimensions?). Something like:

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Step 1: Look at the Timer/Counter Tutorial and the PWM Tutorial in the Tutorials section. You should find some useful examples.

Step 2: Forget the interrupts - you don't need them.
- Set up Timer 0 in Phase Correct PWM to generate the "Carrier" waveform.
- Set up Timer 1 in Phase and Frequency Correct PWM to generate the "Modulation" waveform.
- Use a 74HC00 to NAND the signals together. This way you just set and forget your signals. No interrupts required.

Step 3: If you think you *really need* interrupts, then read the data sheet carefully to figure out exactly what timer interrupts are generated when and pick the one you need. Turn Timer 0 on and off simply by setting bits CS2-CS0 to 0 (no clock source). Select a clock source to turn it back on. When you turn it off, the value you store in the OCR will be output.

Step 4: Go back and read the Tutorials and the Data sheet if things don't go as you expect.

Good luck! The AVR timer/counters are fascinating devices and reward careful study.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, doctek. I will go through the manual one more time. I had thought about the ANDing idea in hardware, but I would like to minmize hardware and do it in software instead.

Sorry about not being clear on the specs. of the waveform, Cliff.

In your waveform 50% < M < 85%.
X is 1 kHz and Y is 0.5Hz. So I will have 1 cycle of Y every 2 seconds. In that one cycle, assuming max. 85% duty cycle, I will have max. about 1.7K cycles of the 1kHz signal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right, this is where the confusion started for me. Above you said timer 1 will be your gate and then you set it up as your 1KHz signal.

I would generate the 1KHz signal on timer 0 in PWM output compare mode, you won't need 16 bit timer for that, so you might as well use the 8 bit one.

If you want to turn the timer off in software I think you will need to do it in an interrupt after all. What chip are you using?

I suppose you could try something like this:

if (flag == 1) 
{ 
//start timer 0 with no prescaler 
TCCR0B |= ( 1 << CS00) 
flag = 0; 
OCR1A = m; //on time value
} 

if (flag == 0) 
{ 
TCCR1B |= 0; //stop timer 0 
flag = 1; 
OCR1A = n; //off time value
}

The above would be timer 1's CTC ISR, your duty cycle would be (M/N)*100. (still using clawsons wave picture as the model)

You'll need the 16 bit timer for this since for a 0.5Hz cycle you'll need 1024 prescaler and n and m values of 15625 for a 50% duty cycle.

(16MHz / 1024 = 15625 cycles/second)

flag, m and n would have to be declared volatile.

If you were going to try the hardware route, I think you're right about needing an AND gate, not a NAND gate.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I tried something similar along the lines that you mentioned:

#include 

#include 

#include 

#include 

#include 

 

#define TONE_ON() { PORTB = 0x01;}

#define TONE_OFF(){ PORTB = 0x00;}

 

volatile int count = 0;

 

//set T1 for compare and overflow interrupt

//Use compare interrupt to start T0

//Use overflow interrupt to stop T0

 

void timer_init()

 

   {

 

     TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

 

     sei(); //enable global interrupts

 

 

     TCCR1B |= (1 << CS12) | (0 << CS11) | ( 1 << CS10); //start timer at Fcpu/1024

 

 

     OCR1A = 15625; //Value for 2 seconds or 0.5Hz

 

             return;

 

   }

 

 

 

ISR(TIMER1_COMPA_vect)

 

 {

    count ^= 1; //count will increment every 2 seconds

 

  }

 

 

void beep()

  {

 

             
                   TONE_ON();

                 _delay_ms(0.5);

                  TONE_OFF();

         _delay_ms(0.5);

              // }

     

             return;

   }

                 

 

int main(void)

 

  {

   

     DDRB = 0xFF;

     timer_init();

   

     //beep();

 

       for(;;)

        {

     

         if(count == 1)

                          {

                           

           beep();

                          

          }

        else  

                       

                          {

                           TONE_OFF();

                           //count = 0;

                           }

                }    

 

  }

I am Xoring count to toggle it in the ISR and then checking it in main. But this did not even give a continuous beep on the speaker. Why could that be? I know all the tricks are in the main function.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EDIT// my 1st reply misunderstood your above post..
Does your test "beep" make a sound?

just try looping beep to see if it does what you think it should do 1st.

I'm not sure why you gave up on the initial idea, I think you need to go back to the original plan. Make your 1KHz pulse with timer 0 PWM on the oc0 pin, then start and stop timer 0 with timer1 interrupt.

Last Edited: Thu. May 21, 2009 - 04:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One other idea, instead of stopping and starting timer0. oc0 will only generate a signal if the DDR for its pin is set to output. So to modulate timer 0 you can set and clear its bit in the DDRB register..

If you make timer1 into fast PWM mode, you will have 2 seperate interrupts, overflow and compare, then you will need to use the 2 sepatate ISRs, one to stop and the other to start the 1KHz signal, which ever way you chose, either turn the whole timer 0 on and off, or set the DDR register to out and in, or I just found another, setting com01 turns on non inverting mode, clearing com01 disconnects the timer from the pin, that might be the best way to do it actually...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

one method would be to configure T1 to do both a compare and an overflow interrupt. In one ISR you set the CS0n bits that start T0 and in the other you reset the bits to stop the timer.

Quote:

If you make timer1 into fast PWM mode, you will have 2 seperate interrupts, overflow and compare, then you will need to use the 2 sepatate ISRs, one to stop and the other to start the 1KHz signal,

:-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks vespine and Cliff.

I am going to try the two timer approach first to see if it works and then move on to my PWM approach.

I have two test "devices" a speaker and an LED. They are my scopes for now :)

My plan is to use Timer T0 for the 1 kHz signal to beep my speaker.
Timer T1 will be used to gate T0 output.

I am going to test these independently (divide and conquer) to see if they work. So T0 should beep my speaker and T1 should flash the LED.(on for one second and off for one second)

When both these work independently as expected, I will combine the two and try to make them work.

I have already tested my speaker out and it produces a nice sharp, loud tone with the following code (as mentioned earlier):


  PORTB = 0x00;
 _delay_ms(0.5); 
  PORTB = 0x01; 
 _delay_ms(0.5); 

Now I am trying to do the exact same thing above with the following code:

void timer_init()

   {  
      TCCR0B |= (1 << CS02) | (0 << CS01) | ( 1 << CS00); //start timer at Fcpu/64
      TCCR0A |= (1 << WGM01) | (1 << COM0A0); //CTC and toggle OC1A pin

     OCR0A = 125; //Timer value for 1kHz o/p frequency

   }

int main(void)
   {
      DDRB = 0xFF;
      timer_init();
    
       for(;;)
        {
        }
    }     

But with this code with Timer 0, I get a very soft tone out on the speaker and it is not the same as with the previous code with the delay_ms in it. I have connected the speaker between PB1 and GND (OC0A pin as the output to toggle the speaker).

Are the two codes similar? Or do I have the wrong count?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is one of the few occasions I'd have said it was worth doing battle with the AVR Studio simulator as it has a cycle counter. To get a view on when the output compare and the timer overflow are occuring enable both interrupts and provide "dummy" ISRs for each into which you can put a breakpoint. Then run the code and reset the cycle counter between one overflow and the next or between one compare interrupt and the next - you'll then be able to gauge whether you got the prescaler and OCR sums correct or not.

Only try to build for simulator V2 not simulator V1 even if it means temporarily porting the code to an AVR that is supported by sim V2. I often put a #ifdef based on the same define as used in io.h to determine two different build paths whether building for the "real" AVR or the siulator friendly one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's a great idea, Cliff. Will give it a try. I was using the chip as my simulator till now which is a pain (remove chip from BB, put in programmer, flash it and put it back on BB..ad infinitum).