Как правильно загнать Arduino в сон с пробуждением по watchdog таймеру

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

В google полно примеров, но смущал один факт  - все они не похожи друг на друга. Потратив вечер и окончательно опухнув от зоопарка примеров ушел на три дня в мануалы на Atmega. Предлагаю обсудить мой код.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Стесняюсь спросить, код работает? Довольны? А зачем тогда обсуждать?

ЗЫ. Могли бы и сюда код выложить, чтоб уважительно относится к читателям.

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

enjoyneering пишет:

Предлагаю обсудить мой код.

А я предлагаю не обсуждать.

Ибо, ответ на вопрос

enjoyneering пишет:

Как правильно загнать Arduino в сон?

Может быть только один - никак.

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

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

Код работает. Хотелось бы узнать правильно ли я все делаю?

ЕвгенийП, не горячитесь. Потребителей можно выпаять или купить камень и залить только бутлоадер. В конце концов код можно использовать для attiny, там нет лишних потребителей, в фреймворк под Arduino есть.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Может тогда проще "слезть" с ардуины на другую IDE и уж там "веселицца" ???

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

enjoyneering пишет:
не горячитесь

Да я как-то и не особо.

enjoyneering пишет:
Потребителей можно выпаять или купить камень и залить только бутлоадер.

Так можно и бутлоадер не заливать, только это уже не Ардуино.

Но и в этом случае, я не вижу причин что-то обсуждать. Задача погружения в сон достаточно тривиальна и подробнейшим образом разобрана у Ника Гэммона. Не вижу, о чём там ещё можно говорить

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

С ардуино слезать не хочу. Вот эти все:

WDTCR |= _BV(WDCE) & ~_BV(WDE);

И остальной непонятный qwerty мне совсем не нравится. В arduino если знаешь англиский на уровне 10 классов все функции сразу понятны. Не надо сидеть курить даташиты и разбираться во всех этих WDCE.

Таки да погружение в сон простая опереция если вдумчиво прочел техническую документацию. Но на практике почему-то получается другая картина. В интернете куча примеров не похожих друг на друга и с кучей ошибок. И все зовутся - как загнать arduino в сон. Сразу возникает вопрос, а как правильно то? У Васи или Пети?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

enjoyneering пишет:
Таки да погружение в сон простая опереция если вдумчиво прочел техническую документацию. Но на практике почему-то получается другая картина. В интернете куча примеров не похожих друг на друга и с кучей ошибок. И все зовутся - как загнать arduino в сон. Сразу возникает вопрос, а как правильно то? У Васи или Пети?

правильно в даташите от производителя, а если вася или петя или вы трактуете его по своему, то на практике у каждого своя "картина".

авторов ардуино это тоже может коснутся, с таким подходом.

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

А можно ссылку на код с реализацией правльного сна? Даташит читал - как понял так и написал на github.

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

ну так этож корявый код. зачем вызывать вот это все??

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();
  sleep_cpu (); 

когда можно вызвать одну функцию в теле которой все что выше, влюченно. код получается чище:

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();

или я чего-то упустил?

-NMi-
Offline
Зарегистрирован: 20.08.2018

Ичё... спит у тебя дурдуина, вачдог "перетикал" и чо???   Reset?

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

enjoyneering пишет:

ну так этож корявый код. зачем вызывать вот это все??

когда можно вызвать одну функцию в теле которой все что выше, влюченно. 

или я чего-то упустил?

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

А вообще, я не знаю уровня Вашей квалификации, но вот, при моей, если я вижу что-то в коде Ника, что мне кажется "корявым", я начинаю думать почему он сделал именно так, а не спешу сразу заявить, что там коряво. Это вопрос доверия к профессионализму того, кто написал код. У меня к Нику достаточно доверия, чтобы в первую очередь предположить, что не там коряво, а я чего-то не понял.

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

"Ичё... спит у тебя дурдуина, вачдог "перетикал" и чо???   Reset?"

мне кажется вы слишком много пьете пива на кортах.

теперь по делу - мне кажеться в моем примере камень не должен уходить в RESET. у всей копипасты из гугла да - после срабатывания вачдог камень ребутится. в моем примере я вроде установил все биты правильно и камень стартует с места останова, тем самым экономится больше энергии.

тем кто в теме, проверьте пожалуста установку битов? спасибо.

 

"А вообще, я не знаю уровня Вашей квалификации"

уровень низкий. поэтому я здеь, поэтому ардуино. просто я стараюсь не копипастить, а разбираться почему и зачем?

-NMi-
Offline
Зарегистрирован: 20.08.2018
#include <mega328p.h>

// Watchdog timeout interrupt service routine
interrupt [WDT] void wdt_timeout_isr(void)
{
// Place your code here

}
// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/1024k
// Watchdog Timer interrupt: On
#pragma optsize-
#asm("wdr")
WDTCSR=0x39;
WDTCSR=0x69;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

 

Это с заходом в прерывание перед Reset и сгенерировано самим CvAvr

-NMi-
Offline
Зарегистрирован: 20.08.2018

enjoyneering пишет:

мне кажется вы слишком много пьете пива на кортах.

Не ВСЕМ ёгурты ПОЛЕЗНЫ, втч и пиво!  На кортах:))  Это как, стисняюся, но спрашу:))

А теперь по теме:

Summary of methods

Use as many of the techniques listed here as are practical in your application. They are described in further detail below.

 

  • Run the processor at a lower frequency
  • Run the processor at a lower voltage
  • Turn off unneeded internal modules in software (eg. SPI, I2C, Serial, ADC)
  • Turn off brownout detection
  • Turn off the Analog-to-Digital converter (ADC)
  • Turn off the watchdog timer
  • Put the processor to sleep
  • Don't use inefficient voltage regulators - if possible run directly from batteries
  • Don't use power-hungry displays (eg. indicator LEDs, backlit LCDs)
  • Arrange to wake the processor from sleep only when needed
  • Turn off (with a MOSFET) external devices (eg. SD cards, temperature sensors) until needed

И вачдог оказывается там и не нужен то...

Ну раз на пиво дених нет - читай книжки "накортах" :))

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

давайте разберем

WDTCSR=0x39;
WDTCSR=0x69;

первая строка устанавливает биты в регистре WDTCSR: watchdog биты (WDP3,WDP2,WDP1,WDP0) на 8 сек, WDCE = 1 для записи времени (8сек) в регистр и WDE =1

во второй вы устанавливате WDIE = 1 и высбрасыраете WDCE = 0, остальное не трогаете.

и вот тут я не понимаю. вот что пишет atmel - "If WDIE setWDE is cleared in combination with this setting, the Watchdog Timer is in Interrupt Mode. If WDIE set & WDE is set, the Watchdog Timer is in Interrupt and System Reset Mode

получается WDIE = 1 и WDE =1. те через 8 сек сработает прерывание по таймеру, а потом еще сверху RESET, кторый перезгрузит камень? или я не прав?

 

"И вачдог оказывается там и не нужен то..."

а как вы по таймеру камень будить собираетесь если watchdog отключите, процессор и его таймеры то спят?

 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

enjoyneering пишет:

получается WDIE = 1 и WDE =1. те через 8 сек сработает прерывание по таймеру, а потом еще сверху RESET, кторый перезгрузит камень? или я не прав?

Сначала ISR(WDT_vect) , после его завершения - Reset. Ну, там чтобы в ISR лапой помахать на прощанье или типа того.

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

sadman41 пишет:

Сначала ISR(WDT_vect) , после его завершения - Reset. Ну, там чтобы в ISR лапой помахать на прощанье или типа того.

вот тут то у меня в башке не укладывается. зачем делать RESET? этож лишние телодвижения и жёр батареи. не проще WDIE = 1 и WDE = 0 тогда каждые 8сек машем лапой в ISR и не перегружаем камень. сплошная экономия.

 

sadman41
Offline
Зарегистрирован: 19.10.2016

enjoyneering пишет:

вот тут то у меня в башке не укладывается. зачем делать RESET? 

Этого я не знаю, пусть спорщик объясняет.

 

-NMi-
Offline
Зарегистрирован: 20.08.2018

enjoyneering пишет:

давайте разберем

Я жеж писАл выше: " не все йогурты и не всем полезны" !!!     И на "кортах" с семками то-же не всем "дано" :))

-NMi-
Offline
Зарегистрирован: 20.08.2018

enjoyneering пишет:

первая строка устанавливает биты в регистре WDTCSR: watchdog биты (WDP3,WDP2,WDP1,WDP0) на 8 сек, WDCE = 1 для записи времени (8сек) в регистр и WDE =1

Это, наверное, последствия от долгого сидения "на_кортах"... ну да ладно, поясню: не во все регистры и не с каждого места в памяти можно "так просто" взять и записать. Поэтому сначала "встаём_с_кортов" а уж затем "здороваемся" , так понятнее?

-NMi-
Offline
Зарегистрирован: 20.08.2018

enjoyneering пишет:

вот тут то у меня в башке не укладывается. зачем делать RESET? этож лишние телодвижения и жёр батареи. не проще WDIE = 1 и WDE = 0 тогда каждые 8сек машем лапой в ISR и не перегружаем камень. сплошная экономия.

Это тогда нужно в атмел писать письмо, мол ардуинщики недовольны тем, что:

Стоит также отметить, что при режиме работы (сброс и прерывание) сначала выполняется прерывание, а затем сброс. И если Fuse бит WDTON установлен в 0, в независимости от битов WDE и WDIE регистра WDTCR таймер будет сбрасывать систему по истечении времени на которое он настроен.

 

-NMi-
Offline
Зарегистрирован: 20.08.2018

sadman41 пишет:

Этого я не знаю, пусть спорщик объясняет.

Доступным языком написал?

sadman41
Offline
Зарегистрирован: 19.10.2016

Вопрос о другом был, как я понял.

-NMi-
Offline
Зарегистрирован: 20.08.2018

enjoyneering пишет:

а как вы по таймеру камень будить собираетесь если watchdog отключите, процессор и его таймеры то спят?

Я конечно не знаю, что именно надо от "сонного" проца и вачдога... но примерно предполагаю, откуда растут "ноги".

В сети есть исходник микро uRtOs которая как-раз таки использует WDT в качестве СИСТЕМНОГО таймера. По этому поводу был уже "закус" с местными завсегдатаями,там чот с ШИМ было, точнее с их количеством, ну не суть.

Так вот скажу - штука эта работает и работает очень даже не плохо. Но есть одно большОЕ но - придётся ПОЛОМАТЬ всю парадигму ардуинопрограммирования и только тогда это всё заработает так как надо. Иными словами там уже не будет вашей "любимой" mills и прочего линейного, как многие любят писать по началу. Хотя и тремя светодиодами с delay можно поморгать с разным временем и создать так любимый всеми ардуинщиками "псевдопарралелизЪм", это когда несколько потоков работают "якобы" одновременно.

Засим прощаюся, удачного "дрюканья" WDT :))

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

enjoyneering пишет:
Вот эти все: WDTCR |= _BV(WDCE) & ~_BV(WDE); И остальной непонятный qwerty мне совсем не нравится. В arduino если знаешь англиский на уровне 10 классов все функции сразу понятны. Не надо сидеть курить даташиты и разбираться во всех этих WDCE.

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

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

От power_all_disable();толку не будет: тактирование этих модулей в режиме SLEEP_MODE_PWR_DOWN и так приостановлено. 

И знаете, подобные заявления "Arduino example of the proper and most advanced way to put any AVR based Arduino boards into sleep", типа все дураки, один я молодец, как-то сразу напрягают.

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

"И если не "курить даташиты", то остается ждать пока кто-то напишет нужный тебе код и свернет его в фунцию с понятным названием."

Вот поэтому и курю.

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

Это даже не пример, так памятка для себя чтоб не забыть. Здесь разместил чтоб спрость все ли я правильно сделал с WDTCSR битами? В правильном ли порядке вызываются функции и тд?

Не знал что если использовать SLEEP_MODE_PWR_DOWN, то power_all_disable(); можно не вызывать. Спасибо.

"И знаете, подобные заявления "Arduino example of the proper and most advanced way to put any AVR based Arduino boards into sleep", типа все дураки, один я молодец,"

Есть такое, но на фоне ардуиновской копипасты - это дествительно "proper and most advanced way".

Green
Offline
Зарегистрирован: 01.10.2015

Пример. 

#define WDT_8S            (0<<WDCE | 1<<WDIE | 1<<WDP3 | 0<<WDP2 | 0<<WDP1 | 1<<WDP0)
#define SET_WDT_MODE(x)   (WDTCSR = 1<<WDCE | 1<<WDE, WDTCSR = (x), wdt_reset())


void setup()
{
  SET_WDT_MODE(WDT_8S);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}


void loop()
{
  uint16_t sleep_cycles = SENSOR_PERIOD_S / SENSOR_SLEEP_S;
  while (sleep_cycles--) {
    sleep_enable();
    sleep_bod_disable();
    sleep_cpu();
    sleep_disable();
  }
}


ISR(WDT_vect)
{
}