Wdt_disable почему-то вызывает сработку Watchdog

тестовый скетч, pro mini 8/3.3В, загрузчик OpenCore.
Пока вочдог первый раз не сработал - все ок. После wdt_enable (WDTO_8S) срабатывает через 8 сек и успевает дойти в setup(). Если даже первой строкой в setup() будет wdt_disable() - вочдог не сбрасывается!
Перезапустить его получается только повторно дав wdt_enable (WDTO_8S); wdt_reset();
но если потом пытаться его выключить в setup или main по wdt_disable() - мгновенно ресетится (но если до этой команды после включения питания не было сработки вочдога - все работает). Понимаю что какой-то бит регистра прерываний не устанавливается, но это ж блин штатная библиотека wdt.h…

Всю цепочку рассуждений я не понял (как и что такое загрузчик OpenCore.)
Если не срабатывает wdt_disable(), то возможно потому, что не обнулен флаг WDRF в регистре MCUSR

ошибся с названием. Загрузчик miniCore. Логично было б если в функции wdt.h - wdt_disable регистры сбрасывались… Скопировал wdt.h в скетч в отдельной вкладке и вижу варнинг при компиляции. И как раз в функции wdt_disable. Чего ж варнинга нет при компиляции ее “на месте”.
\wdt.h:496:26: warning: ISO C++1z does not allow ‘register’ storage class specifier [-Wregister]

вот на эту конструкцию ругается, видно изменили что-то в IDE с момента написания wdt.h

	{
        uint8_t register temp_reg;
		__asm__ __volatile__ (
				"in __tmp_reg__,__SREG__"    "\n\t"
				"cli"                        "\n\t"
				"wdr"                        "\n\t"
				"in  %[TEMPREG],%[WDTREG]"   "\n\t"
				"ori %[TEMPREG],%[WDCE_WDE]" "\n\t"
				"out %[WDTREG],%[TEMPREG]"   "\n\t"
				"out %[WDTREG],__zero_reg__" "\n\t"
				"out __SREG__,__tmp_reg__"   "\n\t"
				: [TEMPREG] "=d" (temp_reg)
				: [WDTREG]  "I"  (_SFR_IO_ADDR(_WD_CONTROL_REG)),
				[WDCE_WDE]  "n"  ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE)))
				: "r0"
		);
	}

не вкурю эту асемблерную вставку - почему не нравится компилятору что нужно запомнить регистр как temp_reg.
Убрал “register” - компилятор не ругается, но и не работает. disable приводит к ребуту…

подключил гайверовскую библиотеку вместо стандартной. То же самое… Это что ж, вручную регистры сбрасывать?

Вы несёте какую-то дикую пургу, простите. Попробуйте обходится без слов, значения которых Вы не знаете. Говорите то, что понимаете сами, а не то, что “умно звучит”.

2 лайка
#define _WD_CONTROL_REG WDTCSR
setup(){
  wdt_enable (WDTO_8S);
  wdt_reset();

//------------
       uint8_t _SREG_COPY = SREG;                     // Сохраняем SREG (и настройки глобальных прерываний)
        noInterrupts();                                // Запрещаем глобальные прерывания
        _WD_CONTROL_REG = ((1 << WDCE) | (1 << WDE));  // Разблокировка доступа к watchdog, см. документацию на МК
        _WD_CONTROL_REG = 0x00;                        // Очищаем все настройки watchdog
        SREG = _SREG_COPY;   
//------------------
//.....
}

сброс регистра в 0 (выделено //— вызывает повторную перезагрузку. Если убираю - перезагружается через 8 сек.

а что не так? WDTCSR регистр при сбросе в 0 (из wd_disable от гайвера или более завернутая запись из родной библиотеки wdt.h) вместо того чтобы остановить вочдог перезагружает МК! В тестовом скетче подключен только OLED 1306 и все.

такой скетч

#include <GyverOLED.h>
#include <avr/wdt.h>
unsigned int timer = 0;
GyverOLED<SSD1306_128x32, OLED_NO_BUFFER> oled;

void setup() {
  wdt_enable (WDTO_8S);
//  wdt_disable(); 
  wdt_reset();
         
    uint8_t _SREG_COPY = SREG;                     // Сохраняем SREG (и настройки глобальных прерываний)
    noInterrupts();                                // Запрещаем глобальные прерывания
    _WD_CONTROL_REG = ((1 << WDCE) | (1 << WDE));  // Разблокировка доступа к watchdog, см. документацию на МК
    _WD_CONTROL_REG = 0x00;                        // Очищаем все настройки watchdog
    SREG = _SREG_COPY;      

  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  delay(500);
  oled.init();  // инициализация

 // --------------------------
  oled.clear();   // очистить дисплей (или буфер)
  oled.print("Setup..");
  oled.update();
    wdt_enable (WDTO_8S);
  }

void loop(){
  // Каждую секунду мигаем светодиодом и значение счетчика пишем в Serial
  if(!(millis()%1000)){
    timer++;
  oled.print(timer);
  oled.update();
  digitalWrite(13,LOW);
  }
//  wdt_reset();
}

убираем 26 строку - не ресетится.
убираем строки 11-15 (или их эквивалент стр.8) - ребут 1 раз в 8 секунд - как положено
НЕ убираем ничего - циклический частый ребут после первого, не бутлуп, до строк 11-15 доходит…

Нашел. Нужно сбрасывать еще один флаг регистра
MCUSR &= ~(1 << WDRF); причем ДО вызова wdt_disable ! Получается функция wdt_disable как ориг так и от гайвера неполная. Подсмотрено в каментах по той библиотеке.
И вывод - нужные регистры (или если совсем точно - биты регистров) НЕ СБРАСЫВАЮТСЯ для отключения вочдога в родной библиотеке для 328P

Молодец! Догадался!
И даже себе решение записал…

А что именно это тебе посоветовали в ПЕРВОМ ЖЕ ОТВЕТЕ - не заметил?

2 лайка

Не читатель.

По моему, правильно, когда решением помечается комментарий с развернутым объяснением как была решена задача. Ведь смысл ответа помеченного как решение в том, чтобы перейти на него и сразу все понять (в идеале).

Например в данном конкретном случае - непонятно, что именно было причиной не сброшенного WDRF в MCUSR (если дело в нем). Если используется бутлоадер то этот флаг сбрасывается после ресета, а без ресета он не может появится. Значит или не используется бутлоадер, или бутлоадер какой то особенный или …
Поэтому и сообщение помеченное как решение (на момент написания комментария) в данном случае, это скорее затычка, которая возможно только маскирует проблему.

Пояснение: На момент написания комментария решением было отмечено сообщение # 10 от AVP

Решение #10

Нашел. Нужно сбрасывать еще один флаг регистра
MCUSR &= ~(1 << WDRF); причем ДО вызова wdt_disable ! Получается функция wdt_disable как ориг так и от гайвера неполная. Подсмотрено в каментах по той библиотеке.
И вывод - нужные регистры (или если совсем точно - биты регистров) НЕ СБРАСЫВАЮТСЯ для отключения вочдога в родной библиотеке для 328P

Дополнение. Посмотрел, оказалось, что в загрузчике optiboot_flash из MiniCore 2.2.2 убран сброс WDRF (для данного сценария).