Need to STOP PWM after n pulses

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

Hi Friends,

I need to program Atmega8/16 with PWM but after certain number of pulses I need to stop the PWM.
I have found working code for PWM on the forum.

    // Setup for PWM
    //fast pwm WGM=6, non-inv mode
    TCCR1A=0xA2;
    TCCR1B=(1<<WGM12);

But I am unable to find which interrupt I need to setup to capture the PWM timer overflow (so that I can put a counter in it and disable pwm after certain count).

Could any one point me to some sample code ?

regards
r.o.

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

Read the spec sheet and do it from basic principles?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Oh ya thanks...
That could be the answer for 80% of the questions on the forums.

Atleast you could have told me if this is correct approch or I cant get interrupts for PWM actions. Or I need to implement timer and do it in my timer overflow.

But no! read the spec sheet! That was great help. Thanks and merry xmus to you.

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

Quote:

That could be the answer for 80% of the questions on the forums.


Indeed. (Playing the devil's advocate, what we'll do is parrot a pertinent part of the datasheet. And/or give you a link to PWM in the Tutorials section. And then ask what in particular isn't understood.)

Quote:

Or I need to implement timer

??? Isn't that what you are doing?

Quote:

do it in my timer overflow.

Either overflow or compare match.

But some of the full answer will depend on your AVR frequency and PWM frequency--it will be hard to count pulses and keep up with very fast frequencies.

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

Not clear if you are using CompareA or CompareB register.
If the former, use Timer1 CompareA interrupt.
(See interrupt names in the file "iom8.h")

//The output compare interrupt handler
ISR(TIMER1_COMPA_vect)
{
   ...
}

main()
{
   ...
   //Enable the Output Compare A interrupt
   TIMSK = (1<<OCIE1A);
   ...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or just use the timer overflow interrupt.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:
??? Isn't that what you are doing?

I was not implementing timer , I was trying to setup PWM. Normal timer and PWM are different if I have read the correct data. Am I correct ?

Quote:
But some of the full answer will depend on your AVR frequency and PWM frequency

I have atmega16 at internal 8Mhz Frequency. The Pulses I dont need very high frequency (variable frequency less than 60Hz)

@Visovian Thanks , I had not decided on CompareA or B yet.

From the replies I think setting up PWM is not the correct thing, and I should use timer comparator inttrupt to calculate pulses as well as send pulses.

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

Well, I'm not a PWM expert, but at such low PWM frequencies one could certainly do all of the PWM "manually", in a CTC timer/counter ISR.

Or, set up the PWM to do its thing, and use a T/C CTC Intr to generate an interrupt to manually turn off the PWM signal at the right time.

Or, if you can switch chips, use an Xmega E and use the programmable logic module. Route the PWM signal and the T/C control signal through a logic gate. Half HW and half SW approach.

JC

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

Quote:

I was not implementing timer , I was trying to setup PWM. Normal timer and PWM are different if I have read the correct data. Am I correct ?


All the information for your "PWM not timer" is contained in the datasheet chapter "16-Bit Timer1". There is no chapter on "PWM".

Around the register description in that chapter, there will be a table of Modes of Operation for the timer. Some of those will be PWM.

I don't know how you can make your claim. Indeed, the timer can "do" several things at once--time tick with the overflow (period); input capture; PWM (or otherwise manipulate connected outputs).

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

@theusch Thanks I will read 16-bit timer1 in depth

Quote:
I don't know how you can make your claim. Indeed, the timer can "do" several things at once--time tick with the overflow (period); input capture; PWM (or otherwise manipulate connected outputs).

Sorry if it seemed like claim . I am aware that Timer can be implemented to do PWM. But I wanted to askif I impment PWM can I use any interupt that I can increment my variable and stop PWM after N number of pulses.

I will do it via implementing a normal timer and interrupt.

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

I have written following code using Timer1 comparator A interrupt. This work good when executed independently. It gives problem when I try to execute in my main project which get command from UART and tries read port pins while this timer is being executed. Some commands from UART are not received properly while executing Timer.

Is it due to delay called _delay_ms() in ISR ? Is it wrong to have delay of 500ms in the ISR.
I suspect this might be hampering the UART recive as it is also done via interrupt ISR(USART_RXC_vect)
Could some one point me what I am doing wrong here.

(not pasted main project since it has around 600 lines of code, I will attach it if some one wants to view it)

//Timer independent code
//Variables for Pulse Output
volatile int count_ms,count_pulse,total_pulses,pwm_space;
volatile short int pulse_pin;
//Output Pulse On time width
#define PULSE_ON_WIDTH 500 //This is output pulse width defined in ms
//Port on which output pulse has to be send
#define PULSE_PORT PORTA
#define PULSE_DDR	DDRA

void out_pulse_start(int no_of_pulses,long space_in_pulses,short int pulse_pin_no);
void main()
{
	out_pulse_start(200,1000,1);

	while(1)
	{
		
	}	
}
//This timer1 comparatorA interrupt is used for sending output pulses for defined number of pulses then disable timer1
ISR (TIMER1_COMPA_vect)
{
    // action to be done every 1 ms
	count_ms++;
	if(count_ms>=pwm_space)
	{
		count_ms=0;
		
		PULSE_PORT |= (1<<pulse_pin);
                // SHOULD I USE DELAY IN ISR ????????
		_delay_ms(PULSE_ON_WIDTH);
		PULSE_PORT &= ~(1<<pulse_pin);
		
		count_pulse++;
		if (count_pulse>=total_pulses)
		{
			TCCR1B &= ~(1<<CS12 | 1<<CS11 | 1<<CS10); // Set all CS12,CS11,CS10 bits to zero so that timer would stop
			count_pulse=0;
		}
	}
}

void out_pulse_start(int no_of_pulses,long space_in_pulses,short int pulse_pin_no)
{
	
	total_pulses=no_of_pulses;
	pwm_space=space_in_pulses; // in ms
 	pulse_pin=pulse_pin_no;
	
	PULSE_DDR |= (1<<pulse_pin_no) ; //set pin of pulse port as output
		
	count_pulse=0;
	count_ms=0;
	//OCRn	= ((CPU CLOCK / Prescaller) * time in second)-1
	//		= ((8000000/64)*0.001)-1
	//		= ((125000)*0.001)-1
	//		= 124
	OCR1A = 124;

    TCCR1B |= (1 << WGM12);
    // Mode 4, CTC on OCR1A

    TIMSK |= (1 << OCIE1A);
    //Set interrupt on compare match

    TCCR1B |= (1 << CS11) | (1 << CS10);
    // set prescaler to 64 and start the timer
}//End of out_pulse_start()
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Is it due to delay called _delay_ms() in ISR ? Is it wrong to have delay of 500ms in the ISR.

Not unlikely, and yes.

If your ISR is "hanging" for half a second, how many characters might possibly (try to) arrive at the UART during that time?

Let's be moderate and assume 9600 BPS at the UART. That means perhaps over 500 chars potentially going into the UART over a second, or 250 during your delay. They will not line up gently in the cable and await the UART and your code picking them one by one.. :wink: Mid you, two characters during that delay is enough to topple your application.

You need to redesign your application, especially the ISR. It is often said that an ISR should be "quick in, quick out".

Let the timer just supply a "tick" to the main app, and do the PWM generation in the main() thread of execution.

Another sign of something not being designed right is that the ISR is called every 1 ms, but it has a delay in it for 500 times that time.

Sit down with a pencil and paper, and a nice cup of tea or coffee. Nevermind the computer right now. It is time for you to think.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thanks for your input JohanEkdahl, I will redesign the way I am using ISR.

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

I got inputs from hardware person designing motors and he said typical pulse train would have on time of 0.5ms and off time of 10 ms.

I have rewritten the code avoiding any delay in the timer ISR. It seems to be working fine with the main project also.

Is this correct way of design ? Please provide inputs if possible.

//My Code
/*
 * Timer1Pulses.c
 *
 * Created: 12/27/2013 2:03:57 PM
 *  Author: User
 */ 

// an interrupt is triggered each time the interval occurs.

// this code sets up timer1 for a 0.1ms  @ 8Mhz Clock (mode 4)

#include 
#include 
#include 
#define F_CPU 8000000
volatile int count_100us,count_pulse,total_pulses,pwm_space,on_cnt,off_cnt;
volatile short int pulse_pin;

#define PULSE_ON_WIDTH 5 //This is defined in multiple of 0.1 ms (100uS)

#define PULSE_PORT	PORTA
#define PULSE_DDR	DDRA

void out_pulse_start(int no_of_pulses,long space_in_pulses,short int pulse_pin_no)
{
	
	total_pulses=no_of_pulses;
	pwm_space=space_in_pulses*10; // space_in_pulses is in ms so multiply by 10 to get counter for pwm_space
 	pulse_pin=pulse_pin_no;
	
	PULSE_DDR |= (1<<pulse_pin_no) ; //set pin of pulse port as output
		
	on_cnt=0;	// THis counts till pulse is on    (e.g. for 0.5 ms on_cnt should be 5)
	off_cnt=0;	// This will count till pulse is off (e.g. for 10 ms off_cnt should be 100)
	count_pulse=0;
	count_100us=0;
	//For 1 ms timer
	//OCRn	= ((CPU CLOCK / Prescaller) * time in second)-1
	//		= ((8000000/64)*0.001)-1
	//		= ((125000)*0.001)-1
	//		= 124
	//OCR1A = 124;
	
	// For 0.1 ms timer
	//		= ((8000000/8)*0.0001)-1 = 99
	OCR1A=99;

    TCCR1B |= (1 << WGM12);
    // Mode 4, CTC on OCR1A

    TIMSK |= (1 << OCIE1A);
    //Set interrupt on compare match

    //TCCR1B |= (1 << CS11) | (1 << CS10);
    // set prescaler to 64 and start the timer
	
	PULSE_PORT |= (1<<pulse_pin_no);	// Make bit on and start timer
	TCCR1B |= (1 << CS11); 
	// set prescaler to 64 and start the timer
	
}//End of out_pulse_start()

int main(void)
{


	out_pulse_start(200,10,4);	

	
    sei();
    // enable interrupts


    while (1);
    {
        // we have a working Timer
    }
}

ISR (TIMER1_COMPA_vect)
{
    // action to be done every 100 us (0.1 ms)
	count_100us++;
	
	if ( (PULSE_PORT & (1 << pulse_pin)) > 0)
	{
		// do this if the pulse pin bit is set(1)
		on_cnt++;
		if(on_cnt >= PULSE_ON_WIDTH)
		{
			PULSE_PORT &= ~(1<<pulse_pin);	// Turn off pulse 
			on_cnt=0;
			count_pulse++;
			if (count_pulse>=total_pulses)
			{
				TCCR1B &= ~(1<<CS12 | 1<<CS11 | 1<<CS10); // Set all CS12,CS11,CS10 bits to zero so that timer would stop
				count_pulse=0;
			}			
		}
	}
	else
	{
		// do this if the pulse pin bit is not set(0)
		off_cnt++;
		if(off_cnt >= pwm_space)
		{
			off_cnt = 0;
			PULSE_PORT |= (1<<pulse_pin);	// Turn on pulse 
		} // end of if (off_cnt >= pwm_space)
	} // end of if ( (PULSE_PORT & (1 << pulse_pin)) > 0)
	
} // End of ISR (TIMER1_COMPA_vect)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I got inputs from hardware person designing motors and he said typical pulse train would have on time of 0.5ms and off time of 10 ms.
I wonder what a special motor needs this timing and what is the point of giving it a certain number of pulses.
Step motor?

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

My circuit is giving pulses to Stepper motor driver and the hardware guy has given specification like 200 number of pulses etc.