понедельник, 10 октября 2011 г.

AVR timers: calculate prescalers

Functions below are only for Atmega128, see "bitness" of timers, prescalers values...

When you use AVR timers, you should setup it's prescalers' values. Often, programmers calculates prescaler on the paper and then hardcodes it into the code. And this is done every time for new delay value. This task can be done automatically by next algorithm. Next is the Python prototype of the algorithm.
class Timer:
    freq = 0 # freq. of timer
    bits = 0 # "bitsness" of timer

# We have for example 4 timers
_timers = [Timer(), Timer(), Timer(), Timer()]

def init_timers():
    # setup bitness of the timers
    global _timers
    _timers[0].bits = 256
    _timers[1].bits = 65536
    _timers[2].bits = 256
    _timers[3].bits = 65536

# for Atmega128
def _alarm_setup(timer, D):
    prescales0 = (1, 8, 32, 64, 128, 256, 1024,)
    prescales = (1, 8, 64, 256, 1024,)
    # base freq of timer, the same for all but is possible to specify differents
    freq = 8000000 # Freq. of MCU

    if timer == 0:
        psc = prescales0
    else:
        psc = prescales

    _timers[timer].freq = freq

    T = 1000000 * psc[-1] * _timers[timer].bits / freq
    cycles = D/T
    if cycles:
        D -= cycles*T

    for _psc in psc:
        # T - timer period (step in usec)
        T = 1000000 * _psc * _timers[timer].bits / freq
        # D_T - how many T (timer periods) are in D (delay)
        D_T = float(D)/T
        if D_T <= .5:
            # can not be rounded even to 1, too short delay time!
            return None
        elif D_T > _timers[timer].bits:
            # delay is too long for this prescale value
            continue
        else:
            # bingo!
            cn = _timers[timer].bits - int(D_T) + 1
            prescale = _psc
            return (cn, prescale, cycles)
    return None

# test
init_timers()
print _alarm_setup(0, 10000000)
print _alarm_setup(0, 256)

Function _alarm_setup() returns triplet (start value of timer counter, prescaler value, total cycles of the timer counter). These 3 values defines initial parameters of counter which should count to delay D microseconds. It's possible to define any values of delay time in this manner.
This Python prototype example is only to show idea of algorithm. But next is the real implementation on C for WinAVR:
/* Calculates prescale (divisor of timer: 1,8,...) and start
 * counter value and total cycles number. Returns 0 on success, -1 on faulire.
 * D is the delay in microseconds.  timer is number of timer.
 * Out values are saved in corresponding timerc_t.
 * Atmega128 implementation!!!
 */
int
_alarm_setup(int timer,
             unsigned long D)
{
        int i;
        int max_psc; // max. value of prescaler of timer
        int *psc; // prescalers of timer
        unsigned long T; // period of tick
        unsigned long Tclk; // period of clock
        unsigned long Tall; // period of timer cycle (from 0 to bits)

        psc = _timers[timer].prescalers;
        max_psc = psc[_timers[timer].nprescalers-1];

        /* Base frequency is F_CPU. Real frequency is F_CPU/prescaler.
           One tick occupes 1/freq seconds (freq in MHz). N ticks occupes
           N/freq. N is max ticks number in counter = bits of this counter =
           _timers[timer].bits. So, total time to count all ticks of counter is
           N/freq = N/(F_CPU/prescaler) = N*prescaler/F_CPU. Freq is in MHz, to
           use microseconds instead of seconds, * 1000000.

           T is the total time of count all the counter with slowest freq (with
           last prescaler - max_psc). cycles is how many counter cycles are in
           D with slowest prescaler on this timer-counter.

           Then D set to D without cycles time.
           */

        // 1000000 * max_psc > F_CPU, so T/F_CPU != 0
        T = (1000000 * max_psc / F_CPU) * _timers[timer].bits;
        _timers[timer].cycles = D/T;

        if (_timers[timer].cycles > 0) {
                D -= (_timers[timer].cycles) * T;
                _timers[timer].cycles_prescaler = max_psc;
        }
        else {
                // If does not need cycles, cycles_prescaler will be 0
                // (may be used as flag of this)
                _timers[timer].cycles_prescaler = 0;
        }

        D *= 1000; // in nanoseconds
        Tclk = 1000000000 / F_CPU; // in nanoseconds
        for (i=0; i<_timers[timer].nprescalers; i++) {
                T = Tclk * psc[i]; // time of one tick
                Tall = T * _timers[timer].bits; // time to count all ticks of counter
                if (D > Tall) {
                        // delay D is too long for this Tall
                        continue;
                }
                else {
                        _timers[timer].prescaler = psc[i];
                        // D/T how many ticks in D, cn is ticks from 0
                        _timers[timer].cn = _timers[timer].bits - D/T;
                        return (0);
                }
        }
        return (-1);
}

This function uses global array of timers: _timers. This is the array of the timerc_t structs:
typedef struct timerc_t {
        volatile timer_handler_t alarm_handler;
        volatile unsigned long nover; // number of overflow
        unsigned long bits; // number of bits
        volatile unsigned long cn; // start from this count value
        volatile unsigned long cycles; // cycles number
        volatile int prescaler; // prescaler (1, 8, 32... - depends on arch. and timer)
        volatile int cycles_prescaler; // prescaler (usually 1024) for total counter cycles
        int *prescalers; // array of timer-counter prescalers
        int nprescalers; // length of prescalers' array
} timerc_t; 
Full implementation of timers support for AVR (Atmega128 only at the moment) are here.

Комментариев нет:

Отправить комментарий

Thanks for your posting!