Таймер 2 - головоломка

Green
Offline
Зарегистрирован: 01.10.2015

Захотелось получить 4 мгц на 3 пине. Казалось бы, какие проблемы!

void setup() {
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  TCCR2B = 1<<CS20;              //делитель 1:1
}

void loop() {}

Однако, не тут то было. На выходе 8 мгц.
Вот так время и уходит.)

b707
Offline
Зарегистрирован: 26.05.2017

а почему частота должна быть 4 ?

 OCR2A = 1;                     //частота 4

частота вроде F_CPU / (Prescaler*(OCR +1)) = 16/2 =8

Green
Offline
Зарегистрирован: 01.10.2015

Нет, для CTC: F_CPU / ( 2 * prescaler * (1 + OCR))
Но дело даже не в этом. При любом значении OCR2A частота остаётся 8! 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Green, попробуй  OCR2A = 1;  последней строчкой :)

Green
Offline
Зарегистрирован: 01.10.2015

А почему так?
Я первым делом попробовал:

int main() {
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  TCCR2B = 1<<CS20;              //делитель 1:1
}

И всё ОК.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Green,  это глючок конфигурации таймера. По факту его можно подловить вот так в "чистой" среде:

int main() {
 TCCR2A=1<<WGM20; //это делает ардуина до тебя
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  TCCR2B = 1<<CS20;              //делитель 1:1
}

 

Green
Offline
Зарегистрирован: 01.10.2015

Я это понял когда вставил init() в начало main(). Ну и увидел что там устанавливается ШИМ для таймера2.
Но я то всё инициализирую по новой после этого. Достаточно так.

int main() {
  TCCR2A=1<<WGM20; //это делает ардуина до тебя
  DDRD  = 1<<3;                  //пин
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  OCR2A = 1;                     //частота 4
  TCCR2B = 1<<CS20;              //делитель 1:1
}

Или предварительно сбросить TCCR2A в 0.
Тут ещё момент есть с OCR2B.)

Kakmyc
Offline
Зарегистрирован: 15.01.2018

А почему при OCRA2A=1; должно быть 4Мгц ?
0.0625 мкс на сброс + 0.0625 мкс на отсчёт .
Итого переключение раз в 0.125мкс.
1 000 000мкс/0.125мкс=8 000 000
8Мгц.

Для 4Мгц OCRA2A=3;

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:
А почему при OCRA2A=1; должно быть 4Мгц ?

TCCR2A = 1<<COM2B0 | 1<<WGM21;

эта строчка вроде задает сброс счетчика при совпадении и toogle пина 1 раз за период. В итоге частота получается в 2 раза меньше, чем длина периода

Green
Offline
Зарегистрирован: 01.10.2015

dimax пишет:

Green,  это глючок конфигурации таймера.


Это не глючок - это фича.)))
Всё дело в буферизации OCR в ШИМ режиме.
Получается так, что Ардуино ТАЙНО настраивает Таймер2 на ШИМ, но не запускает его.
Я же, присваивая OCR2A = 1 и находясь в ШИМе, фактически не копирую OCR в регистр сравнения.
И выставляя новый режим, получаю в регистре сравнения 0. Отсюда и 8 мгц на выходе. Отсюда и пофиг что я записываю в OCR2A.
Тут 2 варианта. Или запускать ШИМ, с тем что бы OCR скопировался в ТОПе, или записывать OCR уже ПОСЛЕ изменения режима, как правильно заметил dimax.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:

Тут 2 варианта. 

Есть ещё третий - всегда конфигурировать таймер полностью, не рассчитывая на то, что он там "по умолчанию".

Green
Offline
Зарегистрирован: 01.10.2015

Ну так и конфигурировал бы "полностью", если бы производитель чётко указал последовательность этой конфигурации. А так приходится заниматься раскопками и методом логического тыка.