Сторожевой таймер Watchdog работает в Ардуино?

Тема в разделе "Arduino & Shields", создана пользователем msd, 8 сен 2011.

  1. msd

    msd Нерд

    Попробовал включить в Orduino Nano v1.1 сторожевой таймер, и он действительно срабатывает, так, как надо, т.е. как будто ресетит ардуину, но после этого она почему то зависает. При этом лампочка на d13 начинает моргать, но это уже, наверное, и не важно.
    Модуль подключен к компьютеру через USB. Чтобы вывести в нормальное состояние надо отключить и подключить USB. Почему не работает так, как надо?
     
  2. nailxx

    nailxx Официальный Нерд Администратор

    Что именно делает ваш watchdog с Ардуиной когда триггерится?
     
  3. msd

    msd Нерд

    Код примерно такой:
    Код (Text):
    #include <avr/wdt.h>
     
    int n = 0;

    void setup() {
      Serial.begin(9600);
      wdt_enable (WDTO_2S);
    }

    void loop() {
      ++n;
      Serial.println(n, DEC);
      if(n < 100)
        wdt_reset();
      delay(100);
    }
    Я ожидаю, что поработав примерно 12 сек (10 сек до прекращения выдачи сброса WatchDog и 2 сек до переполнения WatchDog), ардуина сбросится и начнет сначала. Однако через указанное время работа просто останавливается, как будто после срабатывания WatchDog, ардуина зависает.
     
  4. nailxx

    nailxx Официальный Нерд Администратор

    9xA59kK нравится это.
  5. mike124

    mike124 Нерд

    Скоро мозги закипят - на сайте Ардуино все ссылки на загрузчик для Mega 2560 зациклены на одну и ту же страницу, где прошивки загрузчика нет. Подскажите, где он находится - уж больно нужен сторожевой таймер в режиме RESET.
     
  6. mike124

    mike124 Нерд

    В общем, нашел загрузчик для Мега2560: stk500boot_v2_mega2560.hex. Только это не тот, который идет в штатном комплекте к IDE Ардуино - этот почему-то не сбрасывает сторожевой таймер при сбросе через WDT, хотя представленные загрузчики для остальных плат это делают. Почему разработчики так сделали - одному богу известно. По паспорту загрузчик Меги2560 должен быть размером в 8Кбайт, однако stk500-й имеет размер 20Кбайт. Хотел найти родной загрузчик и доработать его, однако его нет нигде, даже hех-файла.

    Пришлось загрузить тот, что нашел. Имея вторую Ардуину сделал программатор, прошив ее соответсвующим примером из Ардуины и перерезав перемычку.

    При прошивке вылезла ошибка верификации. Перепрошивка давала такой же результат. Однако, бутлоадер заработал как надо. Вот пример кода. Если загрузить его в Ардуино с непропатченным загрузчиком, то через 10 сек светодиод на 13 пине начнет мелко моргать, а платка зависнет.

    С пропатченным, после включения 2 раза моргнет бутлоадер, потом 2 сек пауза, потом прога моргнет длинно и коротко, затем, через 6 сек все повторится. Т.е. загрузчик останавливает WDT.

    #include <avr/sleep.h>
    int led = 13;
    int ll;
    void setup()
    {
    pinMode(led, OUTPUT);
    ll = 0;
    delay(2000);
    WDTCSR=0x39;
    WDTCSR=0x29;
    sleep_enable();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    }
    void loop()
    {
    digitalWrite(led, LOW);
    delay(200);
    digitalWrite(led, HIGH);
    delay(1000);
    digitalWrite(led, LOW);
    delay(200);
    digitalWrite(led, HIGH);
    delay(200);
    digitalWrite(led, LOW);
    sleep_cpu();
    }

    Вылез еще один косяк с новым загрузчиком. Теперь платку можно загрузить только через IDE Ардуино, а раньше она грузилать и через avrdude. Сейчас таймаут - и все.
     
  7. dlta_canon

    dlta_canon Нуб

  8. Karabas

    Karabas Гик

    Подскажите вот в таком вопросе начсет сторожевого таймера, от от кварца тактуется или у него свой генератор.
    Поможет ли он при зависании железа?
    Есть пара чипов, вроде бы глючных, я на них собрал простые часики из примера к библиотеке, вобщем где то через сутки они виснут, иногда раньше. Не идут и все, на индикаторе последнее время (оно же время работы). Отдельный светодиод-моргатель тоже не моргает.
    Это происходит как с кварцем, так и от внутреннего генератора.
    Хочу использовать их в какой нибудь мигалке. Носможет ли сторож ее перегрузить, если зависание не программное?
     
  9. mike124

    mike124 Нерд

    Не знаю, может кому понадобится, но если есть программатор, то лучше шить скетчи Ардуино IDE через него. Отличие от стандартного способа прошивки только в том, что во флэш-памяти освобождается место, занятое ранее загрузчиком. Кроме того, начинает работать сторожевой таймер (актуально для Меги2560).
    Вот код со сторожевым таймером на виринге, разработанный в Ардуино IDE, который у меня заработал:
    Код (C++):
    #include <avr/wdt.h>

      uint8_t wd_change_bit = 0;
      uint8_t wd_control_reg = 0;
      uint8_t mcusr = 0;
      uint8_t mcusr_setup = 0;
    void setup() {
      wd_change_bit = _WD_CHANGE_BIT;
      wd_control_reg = _WD_CONTROL_REG;
      mcusr = MCUSR;
      if (MCUSR & 8) // сработал WDT и его надо отключить
       {
        MCUSR &= 0xE0; // код заточен на Мегу 2560
        wdt_reset();
        _WD_CONTROL_REG=0x10;
        _WD_CONTROL_REG=0x00;
       }
      else
       {
        mcusr_setup = MCUSR;
       }
      wdt_disable();
      Serial.begin(9600);
      if (wd_control_reg == 0) // изначальное состояние
       {
        Serial.println("Setup..");
        Serial.print("Init_MCUSR: ");
        Serial.println(mcusr_setup, HEX);
        Serial.print("Init_WD_CHANGE_BIT: ");
        Serial.println(wd_change_bit, HEX);
        Serial.print("Init_WD_CONTROL_REG: ");
        Serial.println(wd_control_reg, HEX);
       }
      else // состояние после срабатывания WDT
       {
        Serial.println("--------------------------------------------");
        Serial.println("Watchdog reset.");
        Serial.print("RESET_MCUSR: ");
        Serial.println(mcusr, HEX);
        Serial.print("RESET_WD_CHANGE_BIT: ");
        Serial.println(wd_change_bit, HEX);
        Serial.print("RESET_WD_CONTROL_REG: ");
        Serial.println(wd_control_reg, HEX);
     
       }

    // состояние после выключения WDT
      Serial.println("Watchdog disabled.");
      Serial.print("dis_MCUSR: ");
      Serial.println(MCUSR, HEX);
      Serial.print("dis_WD_CHANGE_BIT: ");
      Serial.println(_WD_CHANGE_BIT, HEX);
      Serial.print("dis_WD_CONTROL_REG: ");
      Serial.println(_WD_CONTROL_REG, HEX);
      pinMode(LED_BUILTIN, OUTPUT);

      Serial.println("Wait 5 sec..");
      delay(5000); // Задержка, чтобы было время перепрошить устройство в случае bootloop
      wdt_enable (WDTO_8S); // Для тестов не рекомендуется устанавливать значение менее 8 сек.

    // состояние после запуска WDT
      Serial.println("Watchdog enabled.");
      Serial.print("en_MCUSR: ");
      Serial.println(MCUSR, HEX);
      Serial.print("en_WD_CHANGE_BIT: ");
      Serial.println(_WD_CHANGE_BIT, HEX);
      Serial.print("en_WD_CONTROL_REG: ");
      Serial.println(_WD_CONTROL_REG, HEX);
      Serial.println("--------------------------------------------");
    }

    int timer = 0;

    void loop(){
      // Каждую секунду мигаем светодиодом и значение счетчика пишем в Serial
      if(!(millis() % 1000))
      {
        timer++;
        if (digitalRead(LED_BUILTIN) == HIGH)
         {
          Serial.println(timer);
         }
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == HIGH ? LOW : HIGH);
        delay(1);
      }
    //  wdt_reset();
    }
    Здесь программа сначала ждет 5 секунд, затем светодиод моргает 4 раза. Потом происходит срабатывание сторожевого таймера.
    Но лучше всего смотреть на мониторе порта. Видно, как меняются регистры при срабатывании WDT.

    За основу был взят код из статьи https://geektimes.ru/post/255800/ , частично измененный по результатам экспериментов на С в CVAVR.