std/timer — Timers

import std/timer

Direct control of the two general-purpose timer/counters. Timer0 is 8-bit (counts and compare values are u8); Timer1 is 16-bit (u16). The module covers prescaler selection, compare values, reading and writing the count, Clear-Timer-on-Compare (CTC) mode, and enabling the compare-A interrupt.

Pair these with an Interrupts isr handler (for example TIMER0_COMPA) to run code at a fixed rate.

Prescaler values

set_prescaler takes the timer’s clock-select value, which both starts the timer and divides the CPU clock. That is why the examples pass 3 (= /64) rather than a frequency. The mapping is the same for Timer0 and Timer1:

Value

Clock source

0

stopped (timer off)

1

clk / 1 (no prescaling)

2

clk / 8

3

clk / 64

4

clk / 256

5

clk / 1024

6

external pin, falling edge

7

external pin, rising edge

The interrupt rate in CTC mode is then F_CPU / prescaler / (compare_a + 1). For example 16 MHz / 64 / (249 + 1) = 1000 Hz, the configuration used below.

Timer0 (8-bit)

@timer0_set_prescaler($prescaler: u8)

Select Timer0’s clock source/prescaler using the timer’s clock-select bit pattern (e.g. the value choosing /1, /8, /64, /256, /1024).

@timer0_set_compare_a($val: u8)

Set the Output Compare A value. In CTC mode the timer resets when the count reaches this value.

@timer0_set_compare_b($val: u8)

Set the Output Compare B value.

@timer0_read() -> u8

Return the current counter value.

@timer0_write($val: u8)

Set the counter to $val.

@timer0_ctc_mode()

Put Timer0 into Clear-Timer-on-Compare (CTC) mode, so it counts up to compare A and resets, giving a periodic tick.

@timer0_enable_compa_int()

Unmask the Timer0 compare-match-A interrupt. The handler still requires the global interrupt enable (@sei) and an isr TIMER0_COMPA (name is device-dependent).

Timer1 (16-bit)

@timer1_set_prescaler($prescaler: u8)

Select Timer1’s clock source/prescaler.

@timer1_set_compare_a($val: u16)

Set the 16-bit Output Compare A value.

@timer1_set_compare_b($val: u16)

Set the 16-bit Output Compare B value.

@timer1_read() -> u16

Return the current 16-bit counter value.

@timer1_write($val: u16)

Set the 16-bit counter to $val.

@timer1_ctc_mode()

Put Timer1 into CTC mode (counts up to compare A and resets).

@timer1_enable_compa_int()

Unmask the Timer1 compare-match-A interrupt.

Example

A 1 kHz tick on an ATmega328P at 16 MHz (16 MHz / 64 / 250 = 1000 Hz):

target atmega328p
import std/timer

ram mut $ticks: u16 = 0            # shared between the ISR and main

isr TIMER0_COMPA {                 # runs on every compare-match
    1 ->+ $ticks                   # count one tick
}

@main {
    @timer0_ctc_mode()             # count up to compare-A, then reset to 0
    @timer0_set_compare_a(249)     # reset after 250 counts (0..249)
    @timer0_set_prescaler(3)       # /64 -> 16 MHz / 64 / 250 = 1000 Hz
    @timer0_enable_compa_int()     # unmask this timer's compare-A interrupt
    @sei()                         # globally enable interrupts
    loop * { }                     # the ISR does the work; main just spins
}