Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Atmega8 PWM timing problems

Status
Not open for further replies.

evilheart

Member level 3
Joined
Sep 3, 2009
Messages
67
Helped
3
Reputation
8
Reaction score
2
Trophy points
1,288
Location
egypt
Activity points
1,955
hi guys

i have done a code for software PWM generator , that uses mainly timer1 for timing ,
but instead of generating just one PWM wave , it generates arbitrary number of waves on any pin , each has its own duty cycle , but all of them have the same frequency.

the code was running accurately on proteus , but when i tested the atmega8 on the oscilloscope , the timing wasn't accurate at all!!!!

the duty cycles had good values that are very near to the actual value ,
the problem was the timing itself , the code should give a PWM wave of period 20 ms , but the atmega8 doesn't give that period!!!
it may give a period of 24 , 28 , or even 29 ms , so each time i restart it i get a different period , and all of them are far away from the right value !!!

i am intending to use this code in controlling servo-motors , as servo motors are controlled just by changing the duty cycles from 5 % to 10 %. i think the timing should be very accurate to get accurate results.

also i am intending to use the same atmega8 in UART communication , if the whole chip Timing is missed up , then i may have problems also with the UART !!!!

any one knows what can be the source of this problem ??? crystal ?? the chip ?? maybe the atmega8 is not reliable enough ???
 

You could pass some of your code. When you were programming the chip did you choose the external oscillator properly? If I remember well it has few possibilities of oscillator configuration. You could pass your configuration as well.
 

thanks Gofs for your reply ,

thats some of the code the initialization function , and functions responsible for controlling the PWM wave

, oscillator fuse configurations : CKOPT , SUT0 , SUT1 , CKSEK(3:0) all unprogrammed ,
i know CKOPT should be programmed for crystal frequency more than 8 MHz , but for some reason , the Atmega8 stop working if i programmed CKOPT. and its working like that with the 10 MHz crystal.

can the crystal get "burned" while soldering ??? i think my soldering is not that good till now , can the the crystal frequency get shifted because of the heat ???


Code:
*
 * PWM_GEN.c
 *
 * Description	:	this file contains the implementation of PWM (pulse width modulation) generator , the generator uses
 *					uses Timer1 to make a PWM wave on arbitrary number of pins , instead of just two bits (OCx) provided
 *					by the hardware , the PWM waves generated will have the same frequency , but each can have its own
 *					Duty cycle , there are also in phase in this version.
 *					This code is made initially as a general PWM generator , but the target is to use it for servo motor
 *					control.	
 * Created: 5/4/2012 9:04:03 AM
 *  Author: ahmed
 */ 

#include "PWM_GEN_config.h"
#include "DIO.h"
#include "std_types.h"
#include <avr/interrupt.h>


/* table containing the properties of each PWM wave (Port , pin number , duty cycle)*/
static PWM_wave PWM_table[ NUM_PWM_waves ];
static U8_t table_counter = 0;

/************************************************************************************************************************
Function	:	void_PWMgen_init

Description	:	initialize timer1 to be used for the PWM generation.

*************************************************************************************************************************/

void void_PWMgen_init(){
	
	/*load the value of OCR1A , which determines the PWM frequency*/
	OCR1A = ( (F_crystal*1000000.0) / (F_PWM*N) ) - 1;
	
	/*No effect on OC1x pins / set FOC1x (Force output compare) pins to zero / set WGM(wave gen. mode) 11,12 */
	/*here we use (WGM 4) : CTC (clear timer on compare match with OCR1A) */
	TCCR1A = 0x00 ;
	
	/*the three most significant bits are out of our operation / set WGM 13,12 / set prescaler value*/
	TCCR1B |= (0x08 | PRESCALER ) ;
	
	/* set the global interrupt enable bit in SREG (status register) */
	sei();
	
	/* enable the input capture interrupt enable , The top value of Timer1 is placed in OCR1A register , so at each time 
	   the T1 counter reaches OCR1Ax , the counter will be reset (timer mode_4 : CTC mode (clear timer on compare match))
	   and this interrupt will be executed  */
	/* Enable the output compare match with (OCR1B) interrupt*/
	TIMSK |= 0x18 ;
	
	/*load the first OCR1B value in table*/
	OCR1B = PWM_table[table_counter].OCR1B_Val;
	
	/*fill the PWM_table values with 0xFFFF as a default value*/
	for (U8_t i = 0 ; i < NUM_PWM_waves ; i++)
	{
		PWM_table[i].OCR1B_Val = 0xFFFF;	
	};
	
};

/*
**************************************************************************************************************************
Function	:	void_PWMgen_OVF_ISR

Description	:	this is the ISR done each overflow , together with the compare match ISR , those procedures will generate
				the PWM waves on the pins , by setting all the pins at each overflow , and reset each pin according to the
				duty cycle of its wave when a matching occurs , each pin have a corresponding compare match value , when
				the counter reach that value , the pin is reset , this produces a PWM wave with certain duty cycle.
**************************************************************************************************************************
*/

void void_PWMgen_OVF_ISR(){
	
	
	/*load the first OCR1B_Val in the table*/
		OCR1B = PWM_table[0].OCR1B_Val;
	
	for(U8_t i = 0 ; i < NUM_PWM_waves ; i++){
						
		/* set all the PWM pins , to start the new cycle*/
		if(PWM_table[i].OCR1B_Val != 0xFFFF)
		void_DIO_write_pin(PWM_table[i].port , PWM_table[i].pin , 1);		
	};
};

/*
**************************************************************************************************************************
Function	:	void_PWMgen_CMatch_ISR

Description	:	this is the procedure done if a compare match is detected , to make PWM waves with certain duty cycle, the
				wave pin is set when the timer overflows , then reset when a compare match occurs with OCR1B , so the value
				in OCR1B controls the duty cycle , where duty = OCR1B / counter TOP value (in OCR1A) , so each PWM wave has
				a certain OCR1B value corresponding to its duty cycle , 
				the PWM waves are sorted in the table according to its OCR1B values , when a a compare match occurs with 
				a certain OCR1B value , its corresponding pin is reset ,
				and the next PWM-wave OCR1B in the table , is loaded to the OCR1B register , so this pin will be reset next
				completing its "High" period , and so on.
				 
**************************************************************************************************************************
*/
void void_PWMgen_CMatch_ISR(){
		 			
	/*reset the current PWM wave pin*/
	void_DIO_write_pin(PWM_table[ table_counter ].port, PWM_table[ table_counter ].pin , 0 );
	
	/*increment table counter , and reset it , if it exceeded the maximum value*/
	table_counter++;
	if(table_counter == NUM_PWM_waves) table_counter = 0;
	
	// if the next table section contain no PWM wave info , then thats the end of the table , reset table_counter.
	if( PWM_table[ table_counter ].OCR1B_Val == 0xFFFF ){		
		table_counter = 0;
	};
	/*load the next PWM-wave OCR1B value in the the table , if the next ORC1A_Val is 0XFFFF , no other compare match
	will occur until the next overflow , and that means we reached the end of the table.*/
	OCR1B = PWM_table[table_counter].OCR1B_Val;	
			
};

/*


/*
***************************************************************************************************************************
Function	:	void_PWMgen_setWave

Description	:	the function set a PWM wave options , calculate the OCR1B_Val in the PWM_table , then sort the table.

Input		:	U8_t *port	:	the address of the port of our wave.
				U8_t pin	:	the pin number of the PWM pin.
				FP32 duty	:	the duty cycle of the wave.
***************************************************************************************************************************
*/

void void_PWMgen_setWave( U8_t *port , U8_t pin , FP32 duty){
	
	for(U8_t i = 0 ; i < NUM_PWM_waves -1 ; i++){
		
		/* If this table section is clear (nothing written)*/
		if(PWM_table[i].OCR1B_Val == 0xFFFF && PWM_table[i].port == 0 && PWM_table[i].pin == 0 ){
			 
			 /*copy the data to the table , sort the table and break the loop*/
			 PWM_table[i].port = port;
			 PWM_table[i].pin = pin;
			 PWM_table[i].OCR1B_Val = ( (duty/100.0) * OCR1A)  ;
			 
			 sort_table();
			 
			 break;
		};
	};
};

/**************************************************************************************************************************/
/*the ISR functions according to GCC compiler syntax*/
/**************************************************************************************************************************/

ISR(TIMER1_COMPA_vect){
	
	void_PWMgen_OVF_ISR();
	
};


ISR(TIMER1_COMPB_vect){
	
	void_PWMgen_CMatch_ISR();
};
 

What is the value of the external crystal? Is this an ATmega8 or maybe an ATmega8L, can you find that out?
If you suspect that the problem could be the external crystal, then why don't you use the internal RC for a test?
Apply proper fuse settings to select the internal RC as clock source and see what happens.
Actually you could use the internal RC until you spot the problem, and then move on to external crystal.
It would be better if you stopped thinking that the problem could be the MCU itself and concentrate on finding out the real cause of the problem! ;-)

https://www.engbedded.com/fusecalc


Hope this helps,
Alexandros
 

I have some advise for you. I don't think that all of them are related with this problem but you should listen to them.

1. Try to make "TCCR1B |= (0x08 | PRESCALER ) ;" at the end of init function because it starts the timer so it should be last.
2. Always first init the data in memory and later init the hardware.
3. Instead writing "( (duty/100.0) * OCR1A)" write "duty * OCR1A / 100" or even make separate two instructions for it - first multiply and second divide it. I noticed that AVR compiler has sometimes problems with this kind of calculation in one instruction. Make sure that this value is correct. If not try to make "duty" as an INTEGER not as FLOATING POINT value and change instruction to "PWM_table.OCR1B_Val = (uint16_t)(((uint32_t)duty * (uint32_t)OCR1A) / 100) ;"
4. Check that all "PWM_table.OCR1B_Val" values are smaller than "( (F_crystal*1000000.0) / (F_PWM*N) ) - 1;" and larger than 0. Thanks to it you will be sure that this table is right.
5. Test it on internal RC oscillator like alexxx said.
6. Generally for first test of your code you should change all memory values (tables) into constant numbers so you will know can it generate fixed PWN. After that you will be sure that the hardware is working properly and later check the tables.

The ISR contruction and timer configuration looks fine for me. Try to make sure that the table is correct.
 

thanks guys for the advice ,

@alexx

yes , i already made sure that it's atmega8 not atmega8L , for the internal oscillator idea, as i know using the internal oscillator can cause problems with reprogramming the chip with my serial programmer , i don't remember why , but when i made wrong fuse configurations that use the internal oscillator (default in avrdude) , i couldn't program it again , and it caused me much trouble until i was able to fix that :(.

i still can't let the possiblity that the problem is in the MCU itself !! because it seems like instability problem , as at each start i get different period , so it's hard to be a software problem.

@Gofs

well , if the table is wrong , i would get wrong but stable results , right ???

the period itself is not stable !! each time i start the chip i get different period , but in all the cases the software which controls the period is the same !!!
which means it's probably hardware problem , but i don't know what can affect the timing ?? (crystal ?bad soldering ?? power issues ? )
 
Last edited:

Try to use internal RC and make sure that you have 100nF capacitor close to its pins. Maybe BOD is set up to maximum value and its resetting the chip because the noise on the power line.

I still think that making the software simpler and trying to run PWM with a constant duty and frequency is a good idea for first debugging. Disposing of each uncertainty and making sure that some part of device is working properly in 100% is a good practice I suppose.

Please inform us about your results.
 
Last edited:

@Gofs


"I still think that making the software simpler and trying to run PWM with a constant duty and frequency is a good idea for first debugging. Disposing of each uncertainty and making sure that some part of device is working properly in 100% is a good practice I suppose."

well , i think that's what i already did in my test , i already had made a test program , where i ran four constant PWM waves on portB (1:4) , they had duty cycles of 20 , 40 , 60 , 80 , and based on this test results i made this post.

as i said the duty cycle was fine , and near the expected values , but the timing itself was wrong , the period and the pulse width both had wrong timing , but the duty cycle is fine.

i think this's what you meant by first debugging , right ?

-----------------------------------------------------------
Try to use internal RC and make sure that you have 100nF capacitor close to its pins. Maybe BOD is set up to maximum value and its resetting the chip because the noise on the power line.
------------------------------------------------------

as i said , i don't want to try this , because it caused problems before , as i still don't remember what's exactly the problem i don't want to risk the chip for just a test.

but the BOD issue looks interesting , i am working on a UART driver now , and it also have some problems that seems to hang the MCU for some reason , and like the other problem , it runs well on proteus , and it's not stable too , it may rarely run well ,

the restarting BOD is one of the kind of problems that i need to test , something that's not in the simulation (which is fine) and somehow random.

although if the chip was restarting , i think the wave form will be broken on the oscilloscope , but that didn't happen on the digital oscilloscope we used , the wave form was clean , only the the timing was wrong , but i don't know maybe the digital oscilloscope itself depends on averaging the signal so it neglected the restarting event ??
 

evilheart said:
i don't want to try this , because it caused problems before , as i still don't remember what's exactly the problem i don't want to risk the chip for just a test.
On the contrary you should risk and destroy many chips for lots of tests. So in all your life from now on you won't ever change clock source because there is a problem you don't remember? Do it again, destroy it, unsolder, resolder, see what you did wrong and never do it again! I have changed clock source in AVR a lot of times without the slightest problem, even though I have not used ATmega8 until now but makes no difference.
In any case, this is a couple of days post. What is the progress you made so far in those days? What have you done to spot the problem? What do you have in mind to do? Gofs is right, try with simple PWM first. You said you tried that. Where? In simulator? Then welcome to the real world! If you tried that on hardware and it worked with simple PWM, then undoubtedly there is a software problem.
Trust me this is not AVR mistake. There are billions of AVRs out there, can you imagine what would happen if they had problematic clock source circuitry? If AVR is malfunctioning, this could happen only because absolute maximum ratings are violated. I would suggest to start from that part of datasheet first.

Wish the best of luck,
Alexandros
 
Last edited:

@ alexx

Gofs is right, try with simple PWM first. You said you tried that. Where? In simulator? Then welcome to the real world!
--------------------------------------------------------------------

i am really got tired of repeating this , it seems that my english is still not that good ??

i said i already tried a test program on the atmega8 , and tested the results using a digital oscilloscope to check the wave form and the timing , i noticed that the timing of the generated "fixed duty cycle" PWM waves was not accurate , while it was running accurately in the simulator , that's why i posted this thread in the first place !!!!!

what i learned while working in projects that a software logical bug will case an "expected "error , and error that happens in certain cases , but it always happens !!!!
while problems that may happen or not , or when the system gives a strange random behavior , that means its probably a hardware issue , Any hardware issue ,
bad components in the market - bad soldering - damaged components during soldering or for any reason - bad designed PCB or high frequency issues.

when you face an unstable problem , then there's something unstable in your system , and it's probably Not the software , not in embedded system as i think !!!!
a single CPU that runs a single simple program and simple algorithm !!

i am out of ideas for now , so i was looking for some hint , a well known hardware problem that cause something like that , someone who worked with PWM hardware before who may faced such a problem .

in the two days ago i was testing a UART software that gives strange and unexpected behavior too , i am thinking of using the internal oscillator , but i have to double check that it won't cause problems with the programmer , the problem is in the fuse bits configuration , it seems it changes from an atmega to another , so that's maybe why you didn't face problems with it before .

, i don't have oscilloscope , i rent it inside electronics shop near the collage , so i have to collect some ideas first before trying again .
 

First debugging maybe is a bad name for that. I am still not perfect in English. What I mean was that I am always trying to back to basics in software when something is wrong with the hardware like in your case. This is my way of debugging problems and I wanted to pass you some advise resulting from my experience. I am always trying to "catch" a software/hardware state/configuration when it is working well and then step by step adding the software/hardware to see at what point it started to be wrong. This is very general advise and I tried to match it to situation described by you. Maybe I didn't understand your problem well. If you still have problems with that pass information what did you do and maybe we will think about other solutions.

Try to connect digital oscilloscope to the power line and measure the minimum value (if this oscilloscope has that possibility) or set the trigger on falling edge and on BOD level and on single trigger so you will know if the voltage will drop in any case. Hope you will resolve the problem.
 

thanks guys for your help and the advice ,

i will try to post the solution if i found it !!!:smile:

thanks again for the help.:-D
 

the problem was solved :-D

it was the atmega8 PCB circuit ,

as i said i was working on UART program , that was causing strange problems too , sometimes the MCU hangs for no reason when i run it. in fact it was most of the time , and the program was running well on proteus .

any way , i was suspecting the circuit because my usual bad soldering , i removed the atmega8 from its PCB circuit and tested it on the bread broad , and the UART program worked very well , so i expected that to be the problem of the PWM timing too.

today i tested both the UART and the PWM waves on the oscilloscope in college , i generated three PWM waves with fixed duty cycles , on pin PB.1 , PB.2 , PB.3 ,
they had (20% , 40% ,60 %) duty cycles respectively ,
the results was very good , and the timing was very good too.
so it seems it was the circuit , i still don't know if it was the soldering / the PCB design that causes such problems in higher frequencies , an way it was solved ,

thanks guys for your help and time.:)
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top