Обработчик прерывания WDT

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Всем привет!

В ходе разбора работы таймера WD, наткнулся на не понятную мне вещь.

Код почему-то работает корректно, несмотря на то, что  в обработчике, я перед изменением регистра

(WDTCSR = 0), не устанавливал в 1 биты WDCE и WDE , как в примере из даташита:

WDTCSR |= (1 < WDCE) | (1 << WDE); И не обнулял перед этим бит WDRF в MCUSR

Если кто знает, объясните пжлст, почему всё-таки останавливается таймер, хотя вроде-как не должен?

 

Это такая особенность работы в прерывании? В даташите про это не нашёл.

Или просто где- то протупил?


//== Прерывание от WDT ========
void setup() {
  Serial.begin(9600);
  delay(300);
    cli(); //==== НАСТРОЙКА WD таймера =======
 // MCUSR &= ~(1<<WDRF);  // необязательно
  WDTCSR |= (1 << WDCE) | (1 << WDE);//разрешаем изменения в настройке WDT
  WDTCSR = 0x47; //WDIE = 1(разреш. прерыван от WDT),WDE = 0(прерывание без сброса)
                 // делитель на 2 сек тайм-аут
  sei();                                                
}

ISR( WDT_vect ) {//если не был сброшен WDT
// asm volatile("wdr\n\t");
//  MCUSR &= ~(1<<WDRF);
//  WDTCSR |= (1<<WDCE) | (1<<WDE); эти строчки оказались ненужными))
  WDTCSR = 0x00; //выключаем WDT
  sei();                   
  Serial.println("ERROR");  //здесь остановить мотор
  while (1); 
}

void loop() {
  int a = 1;
  int b = 3;
  int m = 0;
  Serial.print(a);
  Serial.print(" ");
  Serial.println(b);
  Serial.println(" ");
  
  //asm volatile("wdr\n\t"); //комментируем для проверки 
  
  for(int r = 0; r < 1001; r++){
    for(int c = 0; c < 1001; c++){
      m = a;
      a = b;
      b = m;
    }
  }
  Serial.print(a);
  Serial.print(" ");
  Serial.println(b);
  Serial.println(" ");
}

 

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

P.S. Если что плата Pro Mini, с загрузчиком от Uno (optiboot_atmega328)     16MHz

Upper
Offline
Зарегистрирован: 23.06.2020

У вас WDT в режиме прерываний. Записью WDTCSR = 0 вы запрещаете прерывания записывая WDIE=0 (для этого WDCE не важен).

Выведите значение WDTCSR после ERROR и посмотрите.
Serial.println(WDTCSR,HEX);

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Upper пишет:

У вас WDT в режиме прерываний. Записью WDTCSR = 0 вы запрещаете прерывания записывая WDIE=0 (для этого WDCE не важен).

 Выводил WDTCSR в сериал , сразу после входа в обработчик (sei() добавил конечно) WDTCSR = 71;

(0x47 как в Сетапе), а после ERROR  WDTCSR= 7;

P.S. Спасибо, что разъяснили, почему программа работает - т.к. WDIE=0 это теперь понятно, но почему WDTCSR = 7;  ?

P.P.S. Ещё раз спасибо, во всём разобрался. Так и должно работать.Теперь всё ясно

P.P.P.S. Что интересно, про WDIE в даташите написано, что

Выполнение соответствующего вектора прерывания автоматически очистит WDIE и WDIF аппаратно

Но, видимо это происходит уже после выхода из обработчика.

Upper
Offline
Зарегистрирован: 23.06.2020

Дим-мычъ пишет:

P.P.P.S. Что интересно, про WDIE в даташите написано, что

Выполнение соответствующего вектора прерывания автоматически очистит WDIE и WDIF аппаратно

Но, видимо это происходит уже после выхода из обработчика.

Видимо это справедливо для режима "Interrupt and System Reset" т.е. когда WDE=1

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Upper пишет:

Видимо это справедливо для режима "Interrupt and System Reset" т.е. когда WDE=1

 Вы правы. Если в Сетапе установить WDE = 1, то , как и положено, сначала отрабатывает прерывание, а затем ресет и так по кругу. В обработчик приходит и уходит WDTCSR = 15; (В1111), что значит ,что WDIE = 0;(хотя в сетапе было WDIE = 1).

В Сетап же ,естественно, после ресета, приходит до настройки WDTCRS = 0;

Ещё раз спасибо, помогли разобраться.