Focused on Your Needs
6. Configure the Operation Frequency
This tutorial is to configure the operation frequency without going to the fuse setting.
The CKDIV8 Fuse determines the initial value of the CLKPS bits. If CKDIV8 is unprogrammed, the CLKPS bits will be reset to “0000”. If CKDIV8 is programmed (factory default), CLKPS bits are reset to “0011”, giving a division factor of 8 so that the operation frequency is only 1MHz while the CPU frequency is 8MHz. This can be changed through the program without going to the fuse setting.
Example 1: Clock Prescaler Select
CLKPS[3:0] Clock Division Factor
0000 1
0001 2
0010 4
0011 8
0100 16
0101 32
0110 64
0111 128
1000 256
In order to change the operation frequency, the Clock Prescaler Register CLKPR need to be set.
Example 2: Clock Prescaler Register
Bit 7 6 5 4 3 2 1 0
CLKPR: CLKPCE - - - CLKPS3 CLKPS2 CLKPS1 CLKPS0
The CLKPCE bit must be written to logic one to enable change of the CLKPS bits. The CLKPCE bit is only updated when the other bits in CLKPR are simultaneously written to zero. CLKPCE is cleared by hardware four cycles after it is written or when CLKPS bits are written.
Example 3: Set the clock prescaler to 1
#define F_CPU 8000000ul //This may be required for setting the clock Prescaler
#include <avr/io.h>
int main(void)
{
CLKPR = 1 << CLKPCE;
CLKPR = 0; //set clock Prescaler to 1
DDRB |= 1 << 1 | 1 << 2; //Set OC1A and OC1B pins (PB1 and PB2 in ATmega328P) as an output
TCCR1A |= 1 << WGM11; //set fast PWM Mode with TOP at ICR1
TCCR1B |= 1 << WGM12 | 1 << WGM13; //set fast PWM Mode with TOP at ICR1
TCCR1A |= 1 << COM1A1 | 1 << COM1A0; //Set to inverting mode on OC1A
TCCR1A |= 1 << COM1B1 | 1 << COM1B0; //Set to inverting mode on OC1B
TCCR1B |= 1 << CS10; //Set the prescaler to 1
ICR1 = 1999; // Set TOP value, the PWM frequency is 8,000,000/2000 = 4000 Hz
OCR1A = ICR1 - 1500; //Pulse goes up after 500 counts
OCR1B = ICR1 - 500; //Pulse goes up after 1500 counts
while (1) {}
}
Another way is to include <avr/power.h> and use the corresponding command. This tutorial will not dig up into this method. All standard AVR header files are available at https://www.nongnu.org/avr-libc/user-manual/modules.html.
Example 4: Alternative way to set the clock prescaler to 1
#include <avr/power.h>
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
clock_prescale_set(clock_div_1); //set the clock prescaler to 1
DDRB |= 1 << 1 | 1 << 2; //Set OC1A and OC1B pins (PB1 and PB2 in ATmega328P) as an output
TCCR1A |= 1 << WGM11; //set fast PWM Mode with TOP at ICR1
TCCR1B |= 1 << WGM12 | 1 << WGM13; //set fast PWM Mode with TOP at ICR1
TCCR1A |= 1 << COM1A1 | 1 << COM1A0; //Set to inverting mode on OC1A
TCCR1A |= 1 << COM1B1 | 1 << COM1B0; //Set to inverting mode on OC1B
TCCR1B |= 1 << CS10; //Set the prescaler to 1
ICR1 = 1999; // Set TOP value, the PWM frequency is 8,000,000/2000 = 4000 Hz
OCR1A = ICR1 - 1500; //Pulse goes up after 500 counts
OCR1B = ICR1 - 500; //Pulse goes up after 1500 counts
while (1) {}
}
The results are verified though ATmega 328P. In example 3, #define F_CPU 8000000ul is not required when the PWM output is from OCR1A/OCR1B pin; however, #define F_CPU 8000000ul may be required when the PWM output is other I/O pins.