16-bits Fast PWM mode on the Atmega 2560

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

Hi everyone!

I'm trying to produce the 16-bits fast PWM mode on the PB7 pin (Atmega 2560).

This is my code:

 


#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define PortInit DDRB|=(1<<7)
#define LedOn	 PORTB|=(1<<7)
#define LedOff	 PORTB&=~(1<<7)

//int TimerCounter=0;

void timer_ini(void)
{

	TCCR1A|=(1<<COM1C1)|(1<<WGM11)|(1<<WGM10);	//	неинверсный режим
	TCCR1B|=(1<<ICNC1)|(1<<ICES1)|(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS11)|(1<<CS10);		// Устанавливаем делитель=1024
	TCNT1H=0x00;
	TCNT1L=0x00;
	ICR1H=0x00;
	ICR1L=0x30;
	OCR1CH=0x00;;
	OCR1CL=0x15;		//

}

int main(void) {
	timer_ini();
	//DDRB|=(1<<PORTB7);
	//LedOff;
	//PORTB^=0x80;	//Меняем состояние вывода

	while(1) {

	}
}

 

As I understood the datasheet, is should work,but it doesn't.

Where is my error in this code?

Thank you in advance:)

This topic has a solution.
Last Edited: Thu. Dec 19, 2019 - 05:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You've selected mode 15, which uses OCR1A as TOP, but you haven't set OCR1A so it has the post-reset default value of 0x0000.

 

You haven't made OC1C an output (PB7), so PWM will not make it to the pin.

 

Why are you bothering with ICNC1 and ICES1?  They have nothing to do with PWM.

 

By the way, don't use |= when configuring registers.  Use =.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Dear joeymorin,

I implement your comments in the code. That is:


#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define PortInit DDRB|=(1<<7)
#define LedOn	 PORTB|=(1<<7)
#define LedOff	 PORTB&=~(1<<7)

//int TimerCounter=0;

void timer_ini(void)
{

	TCCR1A=(1<<COM1A1)|(1<<COM1C1)|(1<<WGM11)|(1<<WGM10);	//	неинверсный режим
	TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS11)|(1<<CS10);		// Устанавливаем делитель=1024
	TCNT1H=0x00;
	TCNT1L=0x00;
	ICR1H=0x00;
	ICR1L=0x30;
	OCR1CH=0x00;;
	OCR1CL=0x15;		//
	OCR1AH=0x00;;
	OCR1AL=0x15;		//

}

int main(void) {
	timer_ini();
	DDRB|=(1<<PORTB7);
	//LedOff;
	//PORTB^=0x80;	//Меняем состояние вывода

	while(1) {

	}
}

 

Unfortunately, it is still does not work.  

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

well, now it's work. 

I chanched the value of OCR1AH (L) and  now i can see a little pulsation using Logic analyser.

This is the code: 


#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>


#define PortInit DDRB|=(1<<7)
#define LedOn	 PORTB|=(1<<7)
#define LedOff	 PORTB&=~(1<<7)

//int TimerCounter=0;

void timer_ini(void)
{
	
	TCCR1A=(1<<COM1A1)|(1<<COM1C1)|(1<<WGM11)|(1<<WGM10);	//	неинверсный режим
	TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS11)|(1<<CS10);		// Устанавливаем делитель=1024
	TCNT1H=0x00;
	TCNT1L=0x00;
	ICR1H=0x00;
	ICR1L=0x30;
	OCR1CH=0x00;;
	OCR1CL=0x15;		//
	OCR1AH=0x00;;
	OCR1AL=0x15;		//
	
}



int main(void) {
	timer_ini();
	DDRB|=(1<<PORTB7);
	//LedOff;
	//PORTB^=0x80;	//Меняем состояние вывода
	
	
	while(1) {
	
	
		
	}
}

But, how i can chance time period and the width of the pulse? No the period is near of 2 seconds.

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

I suggest watching some videos from HumanHardDrive AVR's playlist on youtube about timers and PWM, so you can understand a little better what they do and how to correctly manage those registers.

 

On pages 149 and 148 of the datasheets there is an explanation on how to calculate the value of OCRnx registers for changing the duty-cycle and the period of the fast-PWM mode. HumanHardDrive also talks about on his videos.

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

Iaz5 wrote:
I implement your comments in the code
Not really.

 

Iaz5 wrote:

	DDRB|=(1<<PORTB7);

This part, yes.

 

Iaz5 wrote:

	OCR1AH=0x00;;
	OCR1AL=0x15;		//

Not so much.

 

This sets TOP to be 0x0015.  However, you've also set OCR1C to be the same value, so the PWM duty on OC1C will be 100% i.e. always on i.e. no pulse train at all.  I expect that's not what you want.

 

Iaz5 wrote:
I chanched the value of OCR1AH (L) and  now i can see a little pulsation using Logic analyser.
Except the code you show is identical to your previous code, so I don't really know what you've changed.  I assume you meant to show the you changed the value of OCR1A to be higher than the value of OCR1C.  That would give you the results you've reported.

 

Perhaps explain what you're trying to achieve:

  1. what frequency of PWM are you after?
  2. what duty cycle of PWM are you after?

 

What is the clock speed of your AVR?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Dec 18, 2019 - 07:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Roga, 

thank you for your advice, this is what I really need right now!=)

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

Dear joeymorin,

I'm trying to achive 4-chanel 16-bits PWM in the fast PWM mode. But this is the next step. Right now, I'm trying to produce 1 chanel PWM with the following parameters:

Time period: 2500 microsec.

Width of pulse - 1000 microsec=> duty cycle of PWM is near to 40%.

The clock speed, as I understood this term, is quartz resonator frequency. Am I right? frequency is 16MHz.

 

 

I understood my problem. I don't understand the math of the PWM frequency and duty cycle calculation. 

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Iaz5 wrote:
Time period: 2500 microsec
So that's a frequency of 1,000,000 / 2,500 = 400 Hz.

 

At 16 MHz, you can get 400 Hz with a timer period of 16,000,000 / 400 = 40,000 CPU cycles.

 

With a 16-bit fast PWM timer mode, you can achieve that with a prescaler of 1 (since the timer has a max period of 65,536 ticks).

 

So, set TOP (i.e. OCRC1 if you're using mode 15) to 40,000 - 1 = 39,999 (remember that fast PWM is zero-based), and use 1 << CS10 for a prescaler of 1.  This will give you your desired timer period of 2,500 µs.

 

At 16 MHz, each LSB of the OCRxn registers accounts for 1/16 = 0.0625 µs.  For a 1,000 µs pulse width, you want an OCRxn value of 1000 / 0.0625 - 1 = 15,999.

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Thu. Dec 19, 2019 - 12:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, it works!

Thank you a lot! The 148 page of datasheet is really helped me!