[ Curiosity,Experimentation ]

Random stuff from the parallel universe of Ones and Zeroes

Archive for the ‘avr-gcc’ Category

PWM in AVR

Posted by appusajeev on September 30, 2010

In the last post, we discussed about timers in AVR microcontrollers and how to go about programming them. Presented here is a how-to on generating PWM waves in AVR. PWM waves of required duty cycle can be generating by configuring the timers with suitable values. PWM can be used to control servo motors, perform DAC (Digital to Analogue Conversion) etc.
PWM waves will be available on the OC1A pin (pin 15 on ATMEGA8,  19 on ATMEGA16) once it is setup.

In PWM, we generate square waves whose duty cycle can be varied. Duty cycle refers to the fraction of the time period of the wave for which the signal is in high state (or simply ON state).
For example, for a square wave of period 100ms, if the duty cycle=50%,
the signal will be in high state for precisely 50 ms and in low state for the next 50ms that make up the period.
If the duty cycle =20 %, the signal  will be high for 20ms and low for the remaining 80ms.

An interesting aspect of PWM is that we can actually perform DAC (Digital to Analogue Conversion), the output voltage is proportional to the duty cycle we set. i.e. for example, if the duty cycle is 50%, the average voltage available on the OCA1 pin will be 2.5V  and for duty cycle = 30 %, the output voltage= .3x 5 V = 1.5 V and so on.

PWM modes

There are several modes of PWM generation provided by AVR  which decides the shape of the square wave generated (the placement of the high section in each cycle). The modes are Fast PWM, Phase correct PWM and Phase and Frequency Correct PWM. Each of these is explained with figures below.

Fast PWM

In Fast PWM, the timer starts form zero, sets OC1A pin high and starts counting up. When the count equals the compare value (set in the OCR1A register), the OC1A pin is pulled low and the timer continues counting till TOP, resets to zero and repeats the whole cycle again. This is the normal non-inverted mode of operation. In inverted mode, OC1A is pulled low when counter resets and pulled high when compare match occurs.

Fast PWM mode

Fast PWM mode

Phase Correct PWM

In this mode, when the timer count reaches TOP, it doesn’t reset to 0. Instead, it starts counting down towards zero. While counting up, when the count equals the compare value, the OC1A pin is pulled high and while downcounting, when the count again becomes equal to compare value, the OC1A pin is pulled low. The process repeats again when the count becomes zero.

Phase Correct PWM mode

Phase Correct PWM mode

Phase and frequency correct PWM

This is essentially the same as Phase Correct PWM but has the added feature that we can change the frequency of the square waves at any instant as opposed to the above modes where frequency is constant defined by the relation given in the section below.

Starting PWM generation

First, we need to configure the clock source for the timer. As discussed in the earlier post, a suitable prescaler may be chosen by setting the CS10,CS11,CS12 bits in the TCCR1B register.
The value of prescaler is a factor in the frequency of waves generated. The frequency of generated square wave (independent of the duty cycle) is given by

PWM formula

PWM formula

N is the value of prescaler and TOP is value to which the counter counts and then resets to zero.
In this discussion, we use the timer in mode 5 (refer datasheet), i.e. 8 bit Fast PWM with TOP = 255. This is a fairly simple mode and can be used to control the speed of motors on the go.
This mode can be selected by setting WGM10 bit in TCCR1A register and WGM12 bit in TCCR1B register. 9 bit and 10 bit PWM with TOP=511 and TOP=1023 can be selected by setting suitable WGM (Waveform Generation Mode) bits. Refer datasheet for the values.
Next we need to choose between normal or non-inverted PWM and inverted PWM (described above) . Inverted PWM is nothing but here duty cycle determines the off time of the waveform. Here we choose normal PWM by setting COM1A1 bit in TCCR1A register.

The duty cycle is given by setting a value between 0 and 255 in the OCR1A register (similarly, 0 to 1023 for 10 bit PWM and 0 to 511 for 9 bit PWM). Value of 255 corresponds to a duty cycle of 100 % and value of 0 in OCR1A corresponds to 0 % duty cycle.
ie OCR1A= 255 x duty cycle.
For example, for duty cycles 20 %, 37 %, 70 %, set OCR1A = 51, 94,  178 respectively
In our example given at the bottom, the frequency of waveform generated  = 46.875 KHz

An example

A simple straightforward way to demonstrate PWM is to hook up an LED to the OC1A pin. In PWM generation, since the average voltage is proportional to the duty cycle (DAC in effect), the brightness of the LED is proportional to the duty cycle with the LED being maximum bright at 100% duty cycle (OCR1A=255).
The following program increases the brightness of the LED connected to OC1A pin gradually from zero to maximum and then from maximum to zero and so on. Observe the power LED of your laptop while sleeping (laptop, not you :D). We are reproducing the same.

PWM demo code

PWM demo code

Posted in avr, avr-gcc | Tagged: , | 5 Comments »

Programming the Timers in AVR [avr-gcc]

Posted by appusajeev on July 16, 2010

All the Atmel® AVR microcontrollers have TIMERs as an inbuilt peripheral . They can be used to generate PWM(Pulse Width Modulation)waves, for generating accurately timed pulses and for registering the timestamp of external events(Input capture mode). ATMEGA 16 and ATMEGA 8(which we focus on in this post) microcontrollers have 3 inbuilt timers in them, one 16 bit timer and two 8 bit timers. These timers run independent of the program being executed and are capable of generating interrupts. Here i will be explaining about the 16 bit timer 1 of ATMEGA 8 and the same applies to ATMEGA 16 as well.

A timer (also called as counter) is simply a device that counts upon receiving clock pulses. The timer increments (or decrements in certain cases)its count with each clock tick it receives.  A timer is usually specified by the maximum value to which it can count (called MAX) beyond which it overflows and resets to zero(BOTTOM). Thus an 8-bit timer/counter can count from 0 through 255 and a 16-bit timer/counter can count from 0 through 65,535.
The speed of counting can be controlled by varying the speed of clock input to it. This is done by prescaling the clock of the microcontroller. By prescaling, we feed a fraction of the CPU clock to the timer.

Timer speed =F_CPU / prescaler

where F_CPU is the AVR CPU clock speed.Normal prescaler values are 1,8,64,256 and 1024. For example, for a 1MHZ clock, if prescaler is 64, then timer speed is  1000000/64=15625 i.e.  in one second,  the timer can count from 0 to 15625.
When the timer reaches the maximum value it can count, it is said to overflow and it automatically resets to 0 and starts counting again. We can set an interrupt to occur when the timer overflows.
When the timer 1 overflows, TOV1 bit will be set in the TIFR (Timer Interrupt Flag Register) register which will be cleared automatically when the corresponding ISR executes or it can be cleared by setting TOV1 bit to 1(odd, but that’s how ATMEL guys want us to clear it !).

Starting the timer

A counter starts counting as soon as it is set to use a clock source, by setting a suitable prescaler value bits CS10,CS11 and CS12 in the TCCR1B (Timer Counter Control Register 1 B )register . The instantaneous value of the timer is available anytime in the TCNT (Timer Count) register. Refer datasheet for more information on various bits in the register.

Timer in Compare Mode (CTC mode)

The timer used in above mode is of not much use as such. The AVR timer can be operated in a mode called CTC mode or Clear on Timer Capture mode in which we can set the timer to compare its count with a certain value set in OCR1A (Output Compare Register 1 A) register or OCR1B register and generate an interrupt or manipulate the OC1A or OC1B pin whenever a match occurs (i.e. when TCNT=OCR1A or TCNT=OCR1B).CTC mode can be used to generate accurate timings and square waves of desired frequency.
CTC mode can be enabled by setting WGM 12 bit=1 in TCCR1B register.
When TCNT=OCR1A, the timer resets and starts from 0 again. The value of OCR1A can be changed anytime and the change in the output will be reflected immediately.

toggling OC1A pin in CTC mode

toggling OC1A pin in CTC mode

When a match occurs we can either Set,Clear or toggle the OC1A/OC1B  pin.The action of OC1A pin can be set by setting suitable values for COM1A0 and COM1A1 bits in TCCR1A (Timer Counter Control Register 1 A) register (refer datasheet).

Whenever a compare match occurs, the OCF1A bit will be set in the TIFR(Timer Interrupt Flag Register) which will automatically be cleared when the associated ISR fires or else we have to manually clear it by setting it to 1.

The following example demonstrates CTC mode of Timer 1. An LED is connected to t0 PB1 pin(pin 15) of Atmega8 which flashes at 1 hz.

Atmega8 Timer 1 in CTC toggle mode

Atmega8 Timer 1 in CTC toggle mode

Generating Square Waves

With the OC1A pin set to toggle by setting COM1A0=1 in TCCR1A register, this mode can be used to generate a square wave of required frequency(50% duty cycle only though) by setting a suitable value in the OCR1A register.
As said above, the value of OCR1A can be changed anytime and the change in the output will be reflected immediately

The frequency of the square wave generated is given by

f = F_CPU / (2.prescaler.(1+OCR1A))

Generating Square waves in CTC mode

Generating Square waves in CTC mode

For eg, to generate a 50Hz square wave, set OCR1A=291

Timers and interrupts

AVR timers can generate 3 types of interrupts- Overflow, Compare match and Input Capture (Input capture is a mode in which we can have the value of the  TCNT register copied to the ICR register whenever  a rising/falling edge is found on the ICP1 pin of the ATMEGA) and we can execute a user specified ISR for these as demonstrated.
To enable interrupts, first we have to enable compare match interrupt for  timer 1 by setting OCIE1A (Output Compare A Match Interrupt Enable) bit in the TIMSK register and then we have to enable global interrupts with the sei() macro. For handling overflow interrupts, set TOIE1 bit in TIMSK register to 1.

The following example demonstrates the use of interrupts. The interrupt service routine(ISR) toggles the LED connected to pin 1 of port B.

Timer 1 Interrupt Handling

Timer 1 Interrupt Handling

Posted in avr-gcc | Tagged: , , | 14 Comments »