Скрытый Timer2 в Леонардо/микро

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

После того, как наш коллега kisoft как бы мимоходом сказал что в леонардо/микро на чипе mega32u4 есть скрытый таймер2, не упомянутый ни словом в даташите - меня, как любителя таймеров охватил интерес :) Сходу в инете  ничего не нашёл, а тут вчера смотрел даташит родственного чипа 32U6, а в нём таймер2 прописан. Взял все его данные с надеждой, а вдруг подойдёт , накатал проверочный код -и опа, всё работает :) Итого в леонардо/микро аж 5 таймеров на любой вкус и разрядность (2x8bit, 1x10bit, 2x16bit)

В данном скетче таймер 2 строчит в два своих аппаратных  выхода частотами 8 и 4 МГц.

#define ASSR   (*(uint8_t*)0xB6)
#define OCR2B  (*(uint8_t*)0xB4)
#define OCR2A  (*(uint8_t*)0xB3)
#define TCNT2  (*(uint8_t*)0xB2)
#define TCCR2B (*(uint8_t*)0xB1)
#define TCCR2A (*(uint8_t*)0xB0)
#define TIFR2  (*(uint8_t*)0x37)
//#define TIMSK2 (*(uint8_t*)0x70)

void setup() {
pinMode(2,OUTPUT); //PD1 (OC2B)
pinMode(8,OUTPUT); //PB4 (OC2A)
TCCR2A=B01110011;
TCCR2B=B00001001;
OCR2A=1;
OCR2B=0;
}

void loop() { 
}

 

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

Фига-се, шуточки у Atmel'а! Нарвутся когда-нибудь на хороший судебный иск.

MagicianT
Offline
Зарегистрирован: 03.10.2015

И действительно. ох... удивительно, адреса задекларированы как /* Reserved [0x9E..0xB7] */

Надо полагать, делали-делали и чего-то недоделали, или ляп какой сотворили. А в 32ю6 пофиксили и перевели резёрв в эксплуатацию.

Ночь на дворе, завтра полезу пошарю.

А TIMSK2 чего замаркили, не включается? адрес то его тож,  /* Reserved [0x70] */

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

MagicianT, а  TIMSK2 оказался продефайненым в самой arduino IDE (1.6.8), видимо случайно забыли убрать:)

Я ещё попутно обнаружил, что некоторые регистры из числа RESERVED  (например принадлежащие портам, которых физически нет) вполне рабочие,  и их можно использовать как свои переменные :) В СИ конечно не особо актуально, а вот если кодить на ассемблере, то это полезный ресурс..

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

MagicianT пишет:

Надо полагать, делали-делали и чего-то недоделали, или ляп какой сотворили. А в 32ю6 пофиксили и перевели резёрв в эксплуатацию.

Не, дело не в этом. Похожая ситуация с STM объясняется так. У Атмела, скорее всего, тоже самое.

Краткая выдержка: "Для каждой линейки для каждого корпуса МК при производстве используют одну маску, заряженную по максимуму, т.к. не выгодно иметь для каждой серии свою маску". "Так же пояснили по поводу наличия «несуществующей периферии» — так как маска одна, то и периферия должна быть тоже максимальная. В некоторых случаях ее такой и оставляют (она просто не проходит тесты и никто гарантии на ее работоспособность не дает), а в некоторых случаях при производстве пережигают перемычку и отключают ее (например Crypto/hash processor)".  "Ну да они так и сказали, что они не первые, многие так делают".

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

dimax пишет:

MagicianT, а  TIMSK2 оказался продефайненым в самой arduino IDE (1.6.8), видимо случайно забыли убрать:)

Я ещё попутно обнаружил, что некоторые регистры из числа RESERVED  (например принадлежащие портам, которых физически нет) вполне рабочие,  и их можно использовать как свои переменные :) В СИ конечно не особо актуально, а вот если кодить на ассемблере, то это полезный ресурс..

Хотел почитать дата-шит на энту 32ю6, посмотреть чего там ещё про-апгрейдили.  А нету. Атмел официально на своём веб-ресурсе никогда про 32Ю6 и не слыхивал. Не продаётся ни где. Для вояк чтоль чего-то мутили, или дела у них перед тем как микрочипу продаться совсем плохо шли, и не до новых апгрейдов было, остаётся только догадываться.  

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

ЕвгенийП пишет:

Фига-се, шуточки у Atmel'а! Нарвутся когда-нибудь на хороший судебный иск.

И в чём они будут виноваты? На незадокументированную периферию производитель гарантии не давал. Всё, что в даташите - можно использовать. И, в случае чего, предъявлять претензии к производителю. А вот незадокументированные возможности используются исключительно на свой страх и риск. Производитель за это ответственности не несёт.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Я этот таймер видел в одной из версий ДШ. Сказал одному товарищу, а он уже это проверил и сказал, что всё пашет. Можно посмотреть информацию здесь. Возможно там еще что нибудь найдется, впрочем кто знает.  Дополнительный таймер, дополнительные выходы ШИМ.

 

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

Jeka_M пишет:

И в чём они будут виноваты? На незадокументированную периферию производитель гарантии не давал.

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

Я не теоретизирую, а знаю это точно, т.к. в своё время выступал экпертом в суде (кажется суд штата Мичиган, но могу ошибиться, почти 20 лет назад дело было) где именно по такому обвинению наехали на Microsoft. Они тогда "забыли" документировать MDI (когда он только появился), а сами активно использовали его в своём MS Office.

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

MagicianT, атмел с даташитами страшно мутит, по моему не ходовые МК потихоньку пропадают из его каталогов..   Были всякие меги 161,162,163, -тоже куда то пропали. Хорошо что инет всё хранит, иначе вообще не понятно что делать если редкий МК попался.  Ещё и ошибки постоянно в даташитах, наколотся можно запросто.  Вот в частности вчера заметил в шите от 32U4 регистр OCR44C :)

Этот 4й таймер вообще весь индусский. Режим СТС не документирован никак, но он есть.  А вот ещё коммент к тому-же регистру OCR4C чуть ниже:  "Note that, if a smaller value than three is written to the Output Compare Register C, the value is automatically replaced by three as it is a minimum value allowed to be written to this register"  Пиши в него что хошь, но меньше 3х он никогда не будет. То есть высокие частоты -прощайте. Учитывая что этот таймер может тактироваться от внутреннего PLL 96Мгц это довольно досадная потеря..

kisoft, сходил по ссылке -товарищ Ванямба конечно мощную библу забабахал, всю периферию AVR в неё втянул. Без поллитры как грится не разберёшься, -структура на структуре сидит и структурой погоняет :)

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

dimax пишет:

kisoft, сходил по ссылке -товарищ Ванямба конечно мощную библу забабахал, всю периферию AVR в неё втянул. Без поллитры как грится не разберёшься, -структура на структуре сидит и структурой погоняет :)

Это да, я тогда как раз его либы юзал немного, но сразу наткнулся на отсутствие поддержки Леонардо. Написал, он сделал, потом и про таймер разговор зашел. :) В либах если только хидеры смотреть и то они навороченные у него, есть такое.

А в pins_arduino.h для Leonardo всё аккуратно раздефайнено:

#undef TCCR2A
#undef WGM20
#undef WGM21
#undef COM2B0
#undef COM2B1
#undef COM2A0
#undef COM2A1
#undef TCCR2B
#undef CS20
#undef CS21
#undef CS22
#undef WGM22
#undef FOC2B
#undef FOC2A
#undef TCNT2
#undef TCNT2_0
#undef TCNT2_1
#undef TCNT2_2
#undef TCNT2_3
#undef TCNT2_4
#undef TCNT2_5
#undef TCNT2_6
#undef TCNT2_7
#undef OCR2A
#undef OCR2_0
#undef OCR2_1
#undef OCR2_2
#undef OCR2_3
#undef OCR2_4
#undef OCR2_5
#undef OCR2_6
#undef OCR2_7
#undef OCR2B
#undef OCR2_0
#undef OCR2_1
#undef OCR2_2
#undef OCR2_3
#undef OCR2_4
#undef OCR2_5
#undef OCR2_6
#undef OCR2_7

А запиливать поддержку в ArduinoIDE как то ломает, придет новая версия и всё сначала ковырять, ну его нафиг :) Хотя, возможно, достаточно pins_arduino.h расковырять.

 

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

В общем да восславится  гугль-мугль и пророк его -яндекс. Пять минут поиска, и вуаля -даташит mega32u4 с полностью описанным таймером2 :)

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

Спасибо.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

ЕвгенийП пишет:

А вот как только используют, они попадают под крайне суровый в Америке закон о защите конкуренции, т.к. недокументированные возможности, которые ты используешь сам или твои партнёры, - это способ получить незаконное конкурентное преимущество.

Спасибо, не знал об этом.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Кажется ошибку у мастера заметил, надо  #define TIFR2  (*(uint8_t*)0x17)

Надоумили меня такие дефайны на прямое обращение по адресу, проверил и работает.

//  TCCR2A=B01110011;
  (*(uint8_t*)0xB0) = B01110011;
//  TCCR2B=B00001001;
  (*(uint8_t*)0xB1) = B00001001;

 А то с этими таймерами вечно проблема, пока настроишь как надо все биты, раз 20 перезаливать приходилось. Теперь на лету можно, формат комманд "ab0" - установить значит на TCCR2A, "r" - прочитать, "w10101010" или "w11"  не значащие нули не обязательны - записать. И вперёд с осцилоскопом на ноге, пока не получится желаемый результат-);


#define TIFR2  (*(uint8_t*)0x17)

#define TCCR2A (*(uint8_t*)0xB0)
#define TCCR2B (*(uint8_t*)0xB1)
#define TCNT2  (*(uint8_t*)0xB2)
#define OCR2A  (*(uint8_t*)0xB3)
#define OCR2B  (*(uint8_t*)0xB4)
#define ASSR   (*(uint8_t*)0xB6)

#define TIMSK2 (*(uint8_t*)0x70)


            int         debug_osm         =       0;
    
            String      in_String         =      "";        
            boolean     end_input         =   false;  
            uint8_t    adres_reg         =       0;         

  
void setup(void) {
  Serial.begin(115200);
  in_String.reserve(200);
    
  pinMode(2,OUTPUT); //PD1 (OC2B)
  pinMode(8,OUTPUT); //PB4 (OC2A)

//  TCCR2A=B01110011;
  (*(uint8_t*)0xB0) = B01110011;
//  TCCR2B=B00001001;
  (*(uint8_t*)0xB1) = B00001001;
  
//  OCR2A=1;
  (*(uint8_t*)0xB3) = 1;
//  OCR2B=0;
  (*(uint8_t*)0xB4) = 0;
 
  tmr_init();  
  pinMode(9,OUTPUT); // test ISR

}

void loop()
{  
  uint8_t  back  = 0;
  char *   pEnd;
  uint32_t tempr = 0;

  serialEvent(); 

  if( end_input) {
    char cmd = in_String[0];
    in_String[0] = '+';
    
    if( cmd == 'a' ) {
      adres_reg = strtol( in_String.c_str(), &pEnd, 16);
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      }
    if( cmd == 'r' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      }
    if( cmd == 'w' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      back = strtol( in_String.c_str(), &pEnd, 2);      
      (*(uint8_t*)adres_reg) = back;
      Serial.print(F("\tnew  value: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print( back, BIN);      
      }

    in_String = "";
    end_input= false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    in_String += inChar;
    if (inChar == '\n') {
//    if ((inChar == 10) || (inChar == 13)){
      end_input= true;
    }
  }
}

Да, и кажется что ISR для этого таймера ардуино не понимает, ставишь TIMSK2 по любому из 3-х - сразу виснет. ISR-ы я добавил, надо ещё посмотреть в ардуино ИДЕ.

 

 

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

MagicianT, в даташите 0x17 (0x37)   Где 0x17 -это отремапленный прямой адресс 0x37 . В AVR же два типа адресации памяти, большинство инструкций ассемблера работают с только с регистрами с адресацией до 0x20. А в этой зоне сидят только рабочие регистры R0..R32. Что бы можно было веселее работать и с остальными адресами (вернее только с частью, осчастливили ещё 32 адреса)  сделали двойную адресацию. Поэтому в сводной таблице все "прямые" адреса начинаются с 0x20, а все "кривые" с ноля. Но данный тип адресации в дефайнах подразумевает именно прямую, так что должно работать только с 0x37,  а с 0x17 данные наползут в один из рабочих регистров Rxx и может глюкануть.

 А вот работу с прерываниями этого таймера не тестировал, вполне логично что может быть какой-то баг, из-за которого собссно и "запретили" таймер 2 :-)

MagicianT
Offline
Зарегистрирован: 03.10.2015

А страницу, на которой прописано 0х37 для TIFR2? Я в дата шите для ДУЕ видел -везде все адреса расписаны, а в атмегах ни разу. Тот адрес 0х17 я из iom32u6.h тупо скопировал.

#define TIFR2 _SFR_IO8(0x17)
#define TOV2 0
#define OCF2A 1
#define OCF2B 2
 
А в iom32u4.h 
#define TIFR0 _SFR_IO8(0x15)
#define TOV0 0
#define OCF0A 1
#define OCF0B 2

#define TIFR1 _SFR_IO8(0x16)
#define TOV1 0
#define OCF1A 1
#define OCF1B 2
#define OCF1C 3
#define ICF1 5

#define TIFR3 _SFR_IO8(0x18)
#define TOV3 0
#define OCF3A 1
#define OCF3B 2
#define OCF3C 3
#define ICF3 5

#define TIFR4 _SFR_IO8(0x19)
#define TOV4 2
#define OCF4B 5
#define OCF4A 6
#define OCF4D 7

Логично, что адресса резервированы ?

 

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

Так при наличии даташита зачем теперь по дебрям ползать? )  По сути: - В дуне в каком-то другом файле делается оффсет +0x20, и всё встаёт на свои места :-)

MagicianT
Offline
Зарегистрирован: 03.10.2015

Брешут они часто в даташитах, я уже сталкивалсяне не раз, когда вместо R/W биты обьявлены как R.  Посмотрите к примеру главу 25.9.4 на странице 330. Регистр ADCSRB, бит ADTS3. Даташит любезно предоставленный вами в последнем линке из #11 поста.

Так вот бит там R - read only, а таблица пониже табле 25.6 утверждает что его можно и нужно писать если ацп драйвить от таймера 4. 

Компилеровские файлы тоже не баг-фри, но последнее слово за ними. Поэтому, советую всем, потрошите где у вас там avr-gcc инсталирован , и смотрите iomxxxx.h, про 328 атмегу там тоже есть все данные (iom328p.h). 

 

Update:

Полез ещё раз в iom32u4.h и сразу нашёл почему прерывания не срабатывают, этих строк не хватает:

#define TIMER2_COMPA_vect_num  13
#define TIMER2_COMPA_vect      _VECTOR(13)  /* Timer/Counter2 Compare Match A */
#define TIMER2_COMPB_vect_num  14
#define TIMER2_COMPB_vect      _VECTOR(14)  /* Timer/Counter2 Compare Match B */
#define TIMER2_OVF_vect_num  15

Т.е. в скетче надо верху прилепить также как и для других B0-B6 и иже с ними.

Update-2: прилепил, полный скетч в котором прерывания по оверфлоу, аутпут компере А и Б работают:


#define TIFR2  (*(uint8_t*)0x17)

#define TCCR2A (*(uint8_t*)0xB0)
#define TCCR2B (*(uint8_t*)0xB1)
#define TCNT2  (*(uint8_t*)0xB2)
#define OCR2A  (*(uint8_t*)0xB3)
#define OCR2B  (*(uint8_t*)0xB4)
#define ASSR   (*(uint8_t*)0xB6)

#define TIMSK2 (*(uint8_t*)0x70)

#define TIMER2_COMPA_vect_num  13
#define TIMER2_COMPA_vect      _VECTOR(13)  // Timer/Counter2 Compare Match A 
#define TIMER2_COMPB_vect_num  14
#define TIMER2_COMPB_vect      _VECTOR(14)  // Timer/Counter2 Compare Match B 
#define TIMER2_OVF_vect_num    15
#define TIMER2_OVF_vect        _VECTOR(15)  // Timer/Counter2 Overflow 

    
            String      in_String         =      "";        
            boolean     end_input         =   false;  
            uint8_t     adres_reg         =       0;         

  
void setup(void) {
  Serial.begin(115200);
  in_String.reserve(200);
    
  pinMode(2,OUTPUT); //PD1 (OC2B)
  pinMode(8,OUTPUT); //PB4 (OC2A)

  //  TCCR2A=B01110011;
  (*(uint8_t*)0xB0) = B11110001;
  //  TCCR2B=B00001001;
  (*(uint8_t*)0xB1) = B00000001;
  
  //  OCR2A=1;
  (*(uint8_t*)0xB3) = B00111111;
  //  OCR2B=0;
  (*(uint8_t*)0xB4) = B00011111;
  // TIMSK2 = 1;
  (*(uint8_t*)0x70) = B00000001;

  pinMode(9,OUTPUT); // test ISR
}

void loop()
{  
  uint8_t  back  = 0;
  char *   pEnd;

  serialEvent(); 

  if( end_input) {
    char cmd = in_String[0];
    in_String[0] = '+';
    
    if( cmd == 'a' ) {
      adres_reg = strtol( in_String.c_str(), &pEnd, 16);
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      }
    if( cmd == 'r' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      }
    if( cmd == 'w' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print(back, BIN);
      back = strtol( in_String.c_str(), &pEnd, 2);      
      (*(uint8_t*)adres_reg) = back;
      Serial.print(F("\tnew  value: "));
      back =   (*(uint8_t*)adres_reg);
      Serial.print( back, BIN);      
      }

    in_String = "";
    end_input= false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    in_String += inChar;
    if (inChar == '\n') {
      end_input= true;
    }
  }
}


ISR(TIMER2_COMPA_vect)
{ 
  bitSet(PINB, 5);
}

ISR(TIMER2_COMPB_vect)
{ 
  bitSet(PINB, 5);
}

ISR(TIMER2_OVF_vect)
{ 
  bitSet(PINB, 5);
}

 

blokerun2
Offline
Зарегистрирован: 27.01.2019

Здравствуйте! Я начинающий, почитал этот пост но так и не понял как сделать прерывание по таймеру в Pro micro. Как переделать мой код чтобы по прерыванию выполнялась функция. Или эту библиотеку нельзя будет использовать а работать только с регистрами? Заранее благодарен!

#include <MsTimer2.h>     
#define reversePolarity 100   

void setup() {
MsTimer2::set(reversePolarity, timerInterupt); // set the timer interrupt period and specify the interrupt function
MsTimer2::start(); // enable timer interrupt
pinMode(17, OUTPUT); //setting pin as output
digitalWrite(17, LOW); //set pin low
}

void loop() {
}

void  timerInterupt() {
digitalWrite(17, ! digitalRead(17));  // polarity reversal 
}

 

blokerun2
Offline
Зарегистрирован: 27.01.2019

Нашел библиотеку FlexiTimer2. Похожа на MsTimer2 но работает и на Ардуино про микро.