Таймеры/счётчики в AVR

Обсуждаем контроллеры компании Atmel.
dfxman
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пт окт 20, 2023 16:31:17

Re: Таймеры/счётчики в AVR

Сообщение dfxman »

[uquote="akl",url="/forum/viewtopic.php?p=4793181#p4793181"]Проверил режим 7 таймера 2 с разными прерываниями.[/uquote]
Спасибо. И хотя Вы настраиваете отличные от моей комбинации инвертирование/прерывание ;), вижу подтверждение моих наблюдений. Осталось протестировать оставшиеся FastPWM режимы, но практически уверен, получите такие же результаты, как и у меня.
Аватара пользователя
Starichok51
Модератор
Сообщения: 19040
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Таймеры/счётчики в AVR

Сообщение Starichok51 »

dfxman писал(а):но практически уверен, получите такие же результаты, как и у меня.
у него в тексте нет задержки на 20 мс. поэтому он не сможет получить такие же результаты, как и у тебя.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

dfxman писал(а):...вижу подтверждение моих наблюдений. Осталось протестировать оставшиеся FastPWM режимы, но практически уверен, получите такие же результаты, как и у меня.
Хотел донести до Вас - особенностей в работе всех таймеров (T0, T1 и T2) при одинаково корректных установках нет. В архиве программа работы таймеров Т2 режим 7 и Т1 режим15. На фотке в архиве
верхний луч - импульсы на лапе PD3/OC2B
нижний луч - импульсы на PB2/OC1B
внешняя синхронизация по фронту PD2
скорость развертки 10мкс/дел.
Вложения
TEST_M168_T2_T1.zip
(36.5 КБ) 16 скачиваний
dfxman
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пт окт 20, 2023 16:31:17

Re: Таймеры/счётчики в AVR

Сообщение dfxman »

akl, спасибо, что тратите время на эксперименты. Но Вы меня не до конца поняли, возможно, я стал плохо формулировать... Я не сравниваю таймеры между собой в одних и тех же режимах. Я столкнулся с разной работой таймера в разных подрежимах (назовём так) внутри режима Fast PWM. У таймера 0 и 2 таких подрежимов 2 - 3 и 7, у таймера 1 - 5 (5, 6, 7, 14, 15). По даташиту, принципиальная разница между подрежимами только в значении TOP. Оно либо фиксированное, либо задаётся в регистре OCRxA, либо (у таймера 1) ICR1. Так вот на практике, подрежим TOP=OCRxA работает не так, как остальные, и как я читаю в даташите. В чем разница - я уже писал, скрины с осциллографа приводил. Что может быть понятнее последних скринов и кода, я уж и не знаю.

P.S. Т.е. сравнивать надо 15 и (14 или 7, 6, 5) внутри таймера 1, или 15 таймера 1 и 3 таймера 2. Или 7 таймера 2 и 5 таймера 1. Надеюсь, смысл понятен.
dfxman
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пт окт 20, 2023 16:31:17

Re: Таймеры/счётчики в AVR

Сообщение dfxman »

stm8 ведет себя похоже основным режимам:
СпойлерИзображение
ну и вариант "уравнивания" режимов (1 канал - таймер 1, 15 режим, 2 канал - таймер 2, 3 режим с предварительной установкой TCNT2 в максимальное значение):
СпойлерИзображение
Спойлер

Код: Выделить всё

void startBothTimers(void) {
    cli();

    GTCCR = (1 << TSM) | (1 << PSRASY) | (1 << PSRSYNC);

    // timer 2
    TCCR2A = 0; TCCR2B = 0; TIMSK2 = 0; TIFR2 = 0;
    TCNT2 = 0; OCR2A = 0; OCR2B = 0;
    TCCR2A |= (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
    TIMSK2 |= (1 << OCIE2B); // COMP interrupt to count pulses
    OCR2B = 63;
    TCCR2B |= (1 << CS22); // 64
///////////////
    TCNT2 = 0xff; // try
///////////////
    t2_counts = 5;

    // timer 1
    TCCR1A = 0; TCCR1B = 0; TIMSK1 = 0; TIFR1 = 0;
    TCNT1 = 0; OCR1A = 0; OCR1B = 0; ICR1 = 0; // 16 bit regs
    TCCR1A |= (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
    TCCR1B |= (1 << WGM13) | (1 << WGM12);
    OCR1A = 0xff; // period / frequency
    TIMSK1 |= (1 << OCIE1B); // COMP interrupt to count pulses
    OCR1B = 63; // duty
    TCCR1B |= (1 << CS11) | (1 << CS10); // 64
    t1_counts = 5;

    sei();

    GTCCR = (1 << PSRASY) | (1 << PSRSYNC); // less instructions

}
Вложения
t1_15_t2_3_ff.png
(21.39 КБ) 264 скачивания
t2_c1.png
(18.83 КБ) 268 скачиваний
dfxman
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пт окт 20, 2023 16:31:17

Re: Таймеры/счётчики в AVR

Сообщение dfxman »

Ну и еще немного эмпирики. Имеет значение последовательность инициализации регистров (где бы еще про это указывалось...). Таймер 2, режимы 3 и 7. 4 варианта инициализации. Функции написал на ассемблере, чтобы компилятор не сильно вмешивался. ISR остались такими же, в сишной части, t2_counts всегда 5.
СпойлерИзображение
Изображение
Изображение
Изображение
Изображение
Спойлер

Код: Выделить всё

#include <avr/io.h>

.global start_timer0, start_timer1, start_timer2

#define TCC_A  r18
#define TCC_B  r19
#define DUTY   r20
#define PERIOD r21
#define TMP    r26
#define DLY_H  r30
#define DLY_L  r31

#define PMODE  r24
#define PMIX   r22

#define DUTY_VALUE 127
#define PERIOD_VALUE 255

start_timer0:
    ; in r24 - mode, r22 - mix
    ; clobbers r18-r27, r30-r31 (z)

    ; mix
    ; 1 - tccra - ocrx
    ; 2 - ocrx - tccra
    ; 3 - ocra - tccra - ocrb
    ; 4 - ocrb - tccra - ocra

    ; 3 7
    ldi DUTY, DUTY_VALUE
    ldi PERIOD, PERIOD_VALUE

    cpi PMODE, 3
    breq _t0_m3

    cpi PMODE, 7
    breq _t0_m7

    jmp _t0_exit

_t0_m3:
    ldi TCC_A, (1 << COM0B1) | (1 << WGM01) | (1 << WGM00)
    ldi TCC_B, (1 << CS01) | (1 << CS00)
    rjmp _t0_mix

_t0_m7:
    ldi TCC_A, (1 << COM0B1) | (1 << WGM01) | (1 << WGM00)
    ldi TCC_B, (1 << WGM02) | (1 << CS01) | (1 << CS00)

_t0_mix:
    cli
    ldi TMP, (1 << TSM) | (1 << PSRASY) | (1 << PSRSYNC)
    sts GTCCR, TMP

    clr TMP
    sts TCCR0B, TMP
    sts TCCR0A, TMP
    sts OCR0A, TMP
    sts OCR0B, TMP
    sts TCNT0, TMP
    sts TIMSK0, TMP
    ldi TMP, 0x07
    sts TIFR0, TMP

    sts TCCR0B, TCC_B

    cpi PMIX, 1
    breq _t0_mix_1
    cpi PMIX, 2
    breq _t0_mix_2
    cpi PMIX, 3
    breq _t0_mix_3
    cpi PMIX, 4
    brne _t0_exit

_t0_mix_4:
    sts OCR0B, DUTY
    sts TCCR0A, TCC_A
    sts OCR0A, PERIOD
    rjmp _t0_start

_t0_mix_3:
    sts OCR0A, PERIOD
    sts TCCR0A, TCC_A
    sts OCR0B, DUTY
    rjmp _t0_start

_t0_mix_2:
    sts OCR0A, PERIOD
    sts OCR0B, DUTY
    sts TCCR0A, TCC_A
    rjmp _t0_start

_t0_mix_1:
    sts TCCR0A, TCC_A
    sts OCR0A, PERIOD
    sts OCR0B, DUTY

_t0_start:
    ; sts TCCR0B, TCC_B
    ldi TMP, (1 << OCIE0B)
    sts TIMSK0, TMP
    ldi TMP, (1 << PSRASY) | (1 << PSRSYNC)

    ;sbi _SFR_IO_ADDR(PINB), PB4
    sbi _SFR_IO_ADDR(PIND), PD7

    ; 500us
    ldi  DLY_H, 11 ; 21 ; 1ms
    ldi  DLY_L, 99 ; 199
dly0:
    dec  DLY_L
    brne dly0
    dec  DLY_H
    brne dly0

    ;sbi _SFR_IO_ADDR(PINB), PB4
    sbi _SFR_IO_ADDR(PIND), PD7

    sei
    ; sts GTCCR, r26
    sts GTCCR, TMP

_t0_exit:
    ret

start_timer1:
    ; in r24 - mode, r22 - mix
    ; clobbers r18-r27, r30-r31 (z)

    ; 5 6 7 14 15

    ret

start_timer2:
    ; in r24 - mode, r22 - mix
    ; clobbers r18-r27, r30-r31 (z)

    ; 3 7
    ldi DUTY, DUTY_VALUE
    ldi PERIOD, PERIOD_VALUE

    cpi PMODE, 3
    breq _t2_m3

    cpi PMODE, 7
    breq _t2_m7

    jmp _t2_exit

_t2_m3:
    ldi TCC_A, (1 << COM2B1) | (1 << WGM21) | (1 << WGM20)
    ldi TCC_B, (1 << CS22)
    rjmp _t2_mix

_t2_m7:
    ldi TCC_A, (1 << COM2B1) | (1 << WGM21) | (1 << WGM20)
    ldi TCC_B, (1 << WGM22) | (1 << CS22)

_t2_mix:
    cli
    ldi TMP, (1 << TSM) | (1 << PSRASY) | (1 << PSRSYNC)
    sts GTCCR, TMP

    clr TMP
    sts TCCR2B, TMP
    sts TCCR2A, TMP
    sts OCR2A, TMP
    sts OCR2B, TMP
    sts TCNT2, TMP
    sts TIMSK2, TMP
    ldi TMP, 0x07
    sts TIFR2, TMP

    sts TCCR2B, TCC_B

    cpi PMIX, 1
    breq _t2_mix_1
    cpi PMIX, 2
    breq _t2_mix_2
    cpi PMIX, 3
    breq _t2_mix_3
    cpi PMIX, 4
    brne _t2_exit

_t2_mix_4:
    sts OCR2B, DUTY
    sts TCCR2A, TCC_A
    sts OCR2A, PERIOD
    rjmp _t2_start

_t2_mix_3:
    sts OCR2A, PERIOD
    sts TCCR2A, TCC_A
    sts OCR2B, DUTY
    rjmp _t2_start

_t2_mix_2:
    sts OCR2A, PERIOD
    sts OCR2B, DUTY
    sts TCCR2A, TCC_A
    rjmp _t2_start

_t2_mix_1:
    sts TCCR2A, TCC_A
    sts OCR2A, PERIOD
    sts OCR2B, DUTY

_t2_start:
    ldi TMP, (1 << OCIE2B)
    sts TIMSK2, TMP
    ldi TMP, (1 << PSRASY) | (1 << PSRSYNC)

    ;sbi _SFR_IO_ADDR(PINB), PB4
    sbi _SFR_IO_ADDR(PIND), PD7

    ; 500us
    ldi  DLY_H, 11 ; 21 ; 1ms
    ldi  DLY_L, 99 ; 199
dly2:
    dec  DLY_L
    brne dly2
    dec  DLY_H
    brne dly2

    ;sbi _SFR_IO_ADDR(PINB), PB4
    sbi _SFR_IO_ADDR(PIND), PD7

    sei
    ; sts GTCCR, r26
    sts GTCCR, TMP

_t2_exit:
    ret

Спойлер

Код: Выделить всё

volatile uint16_t t2_counts;

static inline void stop_t2(void) {
    TCCR2B &= 0xf8;
}

ISR(TIMER2_COMPB_vect) {
    if(!--t2_counts) {
        stop_t2();
    }
}
Вложения
t2m7_3.png
(7.96 КБ) 194 скачивания
t2m7_2.png
(8 КБ) 189 скачиваний
t2m7_1.png
(8.37 КБ) 187 скачиваний
t2m3_2.png
(8.26 КБ) 190 скачиваний
t2m3_1.png
(8.32 КБ) 195 скачиваний
Ответить

Вернуться в «AVR»