*
* 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();
};
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.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.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?