тестовый скетч, 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 приводит к ребуту…
подключил гайверовскую библиотеку вместо стандартной. То же самое… Это что ж, вручную регистры сбрасывать?
Вы несёте какую-то дикую пургу, простите. Попробуйте обходится без слов, значения которых Вы не знаете. Говорите то, что понимаете сами, а не то, что “умно звучит”.
#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
Молодец! Догадался!
И даже себе решение записал…
А что именно это тебе посоветовали в ПЕРВОМ ЖЕ ОТВЕТЕ - не заметил?
Не читатель.
По моему, правильно, когда решением помечается комментарий с развернутым объяснением как была решена задача. Ведь смысл ответа помеченного как решение в том, чтобы перейти на него и сразу все понять (в идеале).
Например в данном конкретном случае - непонятно, что именно было причиной не сброшенного WDRF в MCUSR (если дело в нем). Если используется бутлоадер то этот флаг сбрасывается после ресета, а без ресета он не может появится. Значит или не используется бутлоадер, или бутлоадер какой то особенный или …
Поэтому и сообщение помеченное как решение (на момент написания комментария) в данном случае, это скорее затычка, которая возможно только маскирует проблему.
Пояснение: На момент написания комментария решением было отмечено сообщение # 10 от AVP
Решение #10
Нашел. Нужно сбрасывать еще один флаг регистра
MCUSR &= ~(1 << WDRF); причем ДО вызова wdt_disable ! Получается функция wdt_disable как ориг так и от гайвера неполная. Подсмотрено в каментах по той библиотеке.
И вывод - нужные регистры (или если совсем точно - биты регистров) НЕ СБРАСЫВАЮТСЯ для отключения вочдога в родной библиотеке для 328P
Дополнение. Посмотрел, оказалось, что в загрузчике optiboot_flash из MiniCore 2.2.2 убран сброс WDRF (для данного сценария).