Timers in Embedded Systems

Why Timing is Crucial in Embedded Systems?

  • Precise Delays: Required in operations like waiting for a sensor to stabilize.

  • Task Scheduling: Allows multiple tasks to be executed at predictable intervals.

  • Waveform Generation: Generate digital square waves or analog-like signals using PWM.

  • Real-Time Response: Critical in systems like motor control.

/

Why Not Just Use delay()?

  • delay(ms) is blocking: Freezes the entire microcontroller, making multitasking nearly impossible.

  • Inefficient: Wastes CPU cycles doing nothing.

  • Bad Practice for Complex Projects: Leads to bugs and poor responsiveness.

Why Use Hardware Timers Instead?

  • Non-blocking Timing: Continue running other code while waiting for an event using millis() or interrupts.

  • More Accurate: Less affected by other code delays.

  • Versatile: Configurable for periodic interrupts, event counting, PWM signal generation, and custom scheduling.

What is a Timer/Counter?

  • A hardware peripheral built into microcontrollers.

    • Timer Mode: Counts internal clock cycles for time-based operations.

    • Counter Mode: Counts external events/pulses for event-based triggering.

  • Timers operate independently from the CPU once configured, enabling non-blocking multitasking.

Timer vs Counter Modes

Feature

Timer Mode

Counter Mode

Clock Source

Internal clock

External pin (e.g., T0, T1 on Arduino)

Use Case

Delays, PWM, periodic interrupts

Event counting, frequency measurement

Typical Input

System clock (e.g., 16 MHz on Arduino)

Signal from external hardware/sensor

Core Functionalities

  • Start/Stop: Enable or disable counting.

  • Prescaler: Divides the clock to slow down the count.

  • Compare Match: Triggers an action (e.g., interrupt) when the counter reaches a value.

  • Overflow: Resets when the counter exceeds its maximum and may trigger an interrupt.

Clock and Prescaler Concepts

  • Microcontrollers run on a system clock (e.g., 16 MHz).

  • Timers count these pulses to measure time or trigger events.

What is a Prescaler?

  • A hardware divider that slows down the input clock before it reaches the timer.

  • Divides the system clock by a fixed factor (e.g., 8, 64, 256).

  • Why Use a Prescaler?

    • To extend the range of timer-based delays or PWM frequencies.

Example Calculation

  • System clock = 16 MHz, Prescaler = 64

  • Timer input frequency = 16,000,000÷64=250,00016,000,000 ÷ 64 = 250,000 Hz

  • If using an 8-bit timer (max count = 255):

    • Max delay = 255counts×4 μs=1.02255 counts × 4 \,\mu s = 1.02 ms before overflow.

Prescaler Options on Arduino Uno (ATmega328P)

Prescaler Value

Description

1

Fastest (no scaling)

8

Slower timing, more usable

64

Common for millisecond delays

256

Longer delays, lower resolution

1024

Longest delays, coarsest timing

Timer Modes in Arduino Uno (ATmega328P)

  • The Arduino Uno (ATmega328P) has three timers: Timer0, Timer1, and Timer2.

  • Configured in different modes for timing, PWM signals, or delays.

Timer0, Timer1, Timer2

  • Timer0 (8-bit)

    • Bit width: 8-bit, range of 0 to 255

    • Common Use: Used by functions like millis() and delay()

  • Timer1 (16-bit)

    • Bit width: 16-bit, range of 0 to 65535

    • Common Use: For more precise timing and higher resolution

  • Timer2 (8-bit)

    • Bit width: 8-bit, range of 0 to 255

    • Common Use: Additional timing or PWM tasks when Timer0 is already in use

Comparison of Timer0, Timer1, and Timer2

Feature

Timer0 (8-bit)

Timer1 (16-bit)

Timer2 (8-bit)

Bit Width

8-bit

16-bit

8-bit

Range

0 to 255

0 to 65535

0 to 255

Common Uses

Timekeeping, millis(), delay()

Precise timing, PWM generation

Additional PWM or timing

Resolution

1 clock cycle (8-bit)

1 clock cycle (16-bit)

1 clock cycle (8-bit)

PWM Capability

Yes (for basic PWM, limited pins)

Yes (higher resolution PWM, more control)

Yes (additional PWM, more control)

Possible Issues When Timer is Wrongly Chosen

Issue

Consequence

Example

Timer Conflict

Core functions may malfunction

Using Timer0 for PWM causes millis() to fail

PWM Resolution

PWM signal with limited range

Using an 8-bit timer for high-precision PWM

Inaccurate Timing

Time intervals are imprecise

Incorrect timer selection for generating time delays

Best Practices

  • Choose the correct timer for the task.

  • Be aware that Timer0 is shared by core functions like millis() and delay().

  • Avoid using delay() for real-time multitasking; use timers or interrupts instead.

  • Use Timer1 (16-bit) for high-resolution PWM or precise timing.

  • Manage shared timers properly, for example using Timer2 when Timer0 is already in use.

Timer Modes

  • Normal Mode

    • Description: Counts from 0 to max value and overflows back to 0.

    • Common Use: Basic counting and generating interrupts on overflow.

    • Overflow Behavior: Triggers an interrupt or action.

Comparison of Normal Mode on Different Timers

Timer

Bit Width

Range (Counts)

Overflow Behavior

Common Use

Timer0

8-bit

0 to 255

Overflows every 256 clock cycles

General-purpose timing, millis(), delay()

Timer1

16-bit

0 to 65,535

Overflows every 65,536 clock cycles

High-precision timing, PWM

Timer2

8-bit

0 to 255

Overflows every 256 clock cycles

Additional PWM generation

  • CTC (Clear Timer on Compare Match) Mode

    • Counts from 0 to a predefined value (OCRn register).

    • Resets to 0 when the timer's count matches the value in OCRn.

    • Useful for precise time delays or frequencies, like PWM.

When to Use CTC Mode?

  • Precise Time Delays: Blink an LED every 100ms.

  • PWM: Control LED brightness.

  • Generate Regular Interrupts: Read a sensor every 200ms.

  • Non-blocking Delays: Run background tasks while timing continues.

  • Generate Precise Frequencies: 1kHz tone for a buzzer.

When Not to Use CTC Mode?

  • Short Time Intervals: If you need very precise, quick time measurements (in microseconds).

  • Simple Delays: If you need long, simple delays (e.g., waiting a few seconds), using delay() or millis() is easier.

Fast PWM Mode

  • Purpose: Generate high-frequency PWM signals for controlling devices like LEDs and motors.

  • How It Works: Counts from 0 to 255 (8-bit) or 0 to 65535 (16-bit), output changes when counter reaches OCRn.

  • Common Uses: Controlling LED brightness and motor speed.

When to Use Fast PWM Mode:

  • Controlling LED Brightness: Adjust the brightness by changing the duty cycle.

  • Controlling Motor Speed: Change the motor speed by varying the duty cycle.

  • High-Frequency Signals: For tasks needing fast switching, like sensors or audio signals.

  • Power Efficiency: Ideal for low-power applications as it reduces energy use.

When Not to Use Fast PWM Mode:

  • True Analog Signals Needed: PWM isn’t a true analog output, so not suitable if you need a continuous signal.

  • Precise Frequency Control Required: If exact frequency control is crucial, PWM might not be accurate enough.

  • Low-Frequency PWM Needed: Fast PWM is for high frequencies; use simpler modes for low-frequency tasks.

  • Timer Conflicts: Using Fast PWM might interfere with other timing functions like millis() or delay().

Phase Correct PWM Mode

  • Description: Counts up to the maximum value, then counts back down to 0.

  • Common Use: Smoother motor speed control, precise PWM signals (e.g., audio systems).

  • How It Works: Creates a smoother PWM waveform, reducing abrupt changes in the signal.

When to Use Phase Correct PWM Mode:

  • Smooth motor control: Reduces noise and provides smoother speed changes.

  • Precise control: Good for precise devices like servos or audio signals.

  • Low noise: Ideal for applications where noise reduction is important.

When Not to Use Phase Correct PWM Mode:

  • High-speed needs: It works slower than Fast PWM, so it's not ideal for high- frequency tasks.

  • Efficiency is critical: It’s less efficient for fast switching compared to Fast PWM.

  • No need for smooth transitions: If smooth transitions aren’t necessary (like LED dimming), Fast PWM is simpler.

Summary of Timer Modes

Mode

Common Use

Speed

Smoothness

Best For

Not Ideal For

Normal Mode

Basic counting, interrupts

Slow

Abrupt

Simple time intervals

PWM or smooth control

CTC Mode

Time delays, waveform gen

Moderate

Moderate

Precise timing or frequency control

Fast updates or high-speed tasks

Fast PWM Mode

LED dimming, motor control

Fast

Moderate

High-speed PWM signals

Smooth transitions or low-noise tasks

Phase Correct PWM Mode

Motor control, precision PWM

Moderate

Smooth

Smooth, low-noise control

High-speed or efficiency-critical tasks

Understanding Timer Registers

  • Timer Registers are crucial for controlling timer behavior.

  • Essential for advanced time management, event scheduling, and precise control.

TCCRnA (Timer/Counter Control Register A)

  • Purpose: Configures the timer's mode of operation and controls output pins for PWM signals.

  • Common Bits:

    • WGMn3:0 (Waveform Generation Mode bits): Define the mode of operation.

    • COMnA1/0 & COMnB1/0 (Compare Match Output Mode bits): Control the timer's output pin behavior.

TCCRnB (Timer/Counter Control Register B)

  • Purpose: Defines additional settings such as prescaler, clock source, and mode selection.

  • Common Bits:

    • WGMn3:2 (Waveform Generation Mode Bits): Works with TCCRnA's WGMn1:0 to set the timer mode.

    • CSn2:0 (Clock Select Bits): Select the prescaler for the timer.

Common Prescaler Settings for CSn2:0

CSn2:0

Prescaler Value

Timer Frequency

000

No prescaling (1)

Timer counts at system clock speed

001

Prescaler of 8

Slows down the timer by 8 times

010

Prescaler of 64

Slows down the timer by 64 times

011

Prescaler of 256

Slows down the timer by 256 times

100

Prescaler of 1024

Slows down the timer by 1024 times

Timer Count Register (TCNTn)

  • Purpose: Holds the current value of the timer’s count.

  • Example: TCNT1 = 0; – Sets the Timer1 count register to zero.

Output Compare Register (OCRn)

  • Purpose: Used in CTC or PWM mode. The timer compares the value in OCRn with TCNTn.

  • Common Use: CTC Mode - defines the value at which the timer will reset and trigger an interrupt.

  • Example: OCR1A = 124; – Sets Timer1's compare match value to 124.

Timer Interrupt Mask Register (TIMSKn)

  • Purpose: Enables or disables interrupts for the timer.

  • Example: TIMSK1 |= (1 << OCIE1A); – Enables the interrupt for Timer1's compare match A.

Timer Interrupt Flag Register (TIFRn)

  • Purpose: Contains flags that indicate when a timer event has occurred.

  • Example: TIFR1 |= (1 << OCF1A); – Clears the Timer1 Compare Match A flag.

Summary

  • TCCRn: Controls the mode and prescaler of the timer.

  • TCNTn: Holds the current timer value (counts clock cycles).

  • OCRn: Defines when the timer should trigger events

  • TIMSKn: Enables interrupts for the timer.

  • TIFRn: Flags timer events like compare match or overflow.

  • Prescaler: Divides the system clock to adjust the timer’s counting frequency.

Timer Overflow

  • An overflow occurs when the timer’s count reaches its maximum value.

  • 8-bit timers have a max count of 255, 16-bit timers have a max count of 65535.

  • Overflow Event: Triggers an interrupt (if enabled).

Compare Match

  • A compare match occurs when the value of the timer (TCNTn) matches the value stored in the Output Compare Register (OCRn).

  • When this happens, the timer can trigger various actions, including setting flags, generating interrupts, or resetting the timer.

  • Compare Match Interrupt: An interrupt can be triggered when a match occurs, allowing for precise event handling.

Timer Overflow vs Compare Match

  • Timer Overflow: Occurs when the timer’s count exceeds its maximum value.

  • Compare Match: Occurs when the timer's value matches the OCRn register value.
    *

What is a Counter (vs Timer)?

  • A counter is a specialized timer that counts external events or signals, whereas a timer counts clock cycles generated internally.

External Event Counting with Counters

  • A counter is useful when you need to measure or track external occurrences.

  • In microcontrollers like the ATmega328P counters can be tied to specific pins.

  • Example of Counter Usage:

    • Measuring RPM of a motor: The counter increments every time the sensor detects a rotation pulse from a motor.

Using millis() for Non-blocking Delay

  • Non-blocking delay avoids halting the execution of the program while waiting for a delay.

  • millis() returns the number of milliseconds that have passed since the Arduino board was powered up or reset.

  • By comparing the current value of millis() to a previously stored value, you can track elapsed time without stopping the program's flow.

Using micros() for Microsecond Precision

  • micros() returns the number of microseconds since the Arduino.

  • Provides a higher resolution than millis().

  • Useful for measuring short time intervals or controlling time-sensitive events.