月份: 2021 年 4 月

ESP8266 Modules Deep Sleep

No Comments

我的開發板進了 deep sleep mode,離開後是有問題的,是成所謂的僵屍模式,或者就反覆的 reset。研判至今尚未有最佳解法。以下是找到的資料。

  • ESP.deepSleep hangs after wakeup – ESP12F (Working on older chips)
  • 幾種解法:
  • workaround 的程式如下,但似乎不及 deep sleep 的省電程度
  • 增加 pull-up 電阻於 MISO pin
  • 更換不同的 flash chip
  • 強化電源
  • 使用 power down mode,即,軟體控制 EN pin,將使得從 25uA 降為 5uA
  • 其他資訊
  • https://www.esp8266.com/viewtopic.php?f=6&t=17975&p=82063&hilit=deep+sleep#p82063
  • https://www.esp8266.com/viewtopic.php?f=6&t=20648&p=84970&hilit=deep+sleep#p84970
  • https://www.esp8266.com/viewtopic.php?f=6&t=21772&hilit=deep+sleep
  • https://www.esp8266.com/viewtopic.php?p=76989#p77279
  • https://www.esp8266.com/viewtopic.php?f=6&t=22372&hilit=deep+sleep
  • https://www.esp8266.com/viewtopic.php?f=6&t=21007&hilit=deep+sleep
  • https://www.esp8266.com/viewtopic.php?f=6&t=12908&hilit=deep+sleep
#define ets_wdt_disable ((void (*)(void))0x400030f0)
#define ets_delay_us ((void (*)(int))0x40002ecc)

#define _R (uint32_t *)0x60000700
void nkDeepSleep(uint64_t time)
{
    ets_wdt_disable();
    *(_R + 4) = 0;
    *(_R + 17) = 4;
    *(_R + 1) = *(_R + 7) + 5;
    *(_R + 6) = 8;
    *(_R + 2) = 1 << 20;
    ets_delay_us(10);
    *(_R + 39) = 0x11;
    *(_R + 40) = 3;
    *(_R) &= 0xFCF;
    *(_R + 1) = *(_R + 7) + (45*(time >> 8));
    *(_R + 16) = 0x7F;
    *(_R + 2) = 1 << 20;
    __asm volatile ("waiti 0");
}
  • 個人結論
  • deep sleep mode 仍然未成功過;要不是自己醒來成為 zombie mode,要不就是從頭開始執行。不過筆者突破盲腸了。。。
  • deep sleep 只保留了 RTC memory,意謂著 ESP 仍是從頭開始執行而非睡入的那個程序點之後否則 main memory 必然被保留。因此,deep sleep & RTC memory 合用,才有意義。還有當醒來後可省略諸如 wifi rf 的自動調校等動作加速啟動時間;這意謂著有某些資訊是自動被存於 RTC or flash 中的。
  • 因此,爬梳文章未發現筆者想要的答案理所當然。
  • 該注意的是,RST 與 GPIO16 對接以應對 deep sleep wake up,是 deep sleep 的 bug 及官方 workaround 的方式(否則不需用上 GPIO16),因,GPIO16 是預設 internal pull-low 的且唯這支是在 low。簡單推論想像,進入 deep sleep mode 時,RST & RTC rout 並沒有被關電並且開始在計時,GPIO16 也因呼叫而在 DeepSleep() 內被設為相對應的 high,其他 GPIO 保持該準位。當醒來時,所有 GPIO 將先不由得而被重設為預設值(否則 GPIO16 便無用處)但仍保留了 RTC 的電其從未被斷掉過。ESP 將因 RST 被拉 low 而使得重新啟動幸而 RTC 始終活著。若沒有 GPIO16 參與而進入 zombie mode,便是它的 bug。尚忽略一點,GPIO16 尚須回復到 high;前文曾提到了,除了 GPIO4,GPIO5,所有 user GPIOs 都將短暫地被拉 high,包含 GPIO16,boot loader 將於該時間點啟動/系統啟動的真正時間點,並將 GPIO16 拉 high。「筆者後補註:以上是筆者的推測,但有一點顯然與實際不符,即,當 RTC timeout 時,GPIO16 會扯一下,即,它拉了一下 low 看來是與 RTC timeout 相關的。故與預設 pull-low 很可能就沒有關聯性。(又或者筆者誤解了實際狀況,它的實際拉 low,正是預設 pull-low 那個時間點,即,就類似筆者猜測那樣,RTC timeout 純粹讓 CPU 從零位址重新跑扣,因而進入 zombie mode,再因軟體設定的 internal pull-high/low 讓 ESP 真正重設並記錄是由 deep sleep mode 中脫離)」
    當然,要驗證 deep sleep 確實有效果,筆者得寫讀 RTC memory 來確認才行不過,當前筆者不需要它,故日後再看看。
  • 故,除了用上 RTC memory,還有其他用法嗎?這就是筆者當前的結論。
  • 結論:
  • 前面影片中提到,在 deep sleep 前題之下,EN 拉 low 可進入 power down mode 讓功耗降為 5uA 左右並且仍保有 RTC memory;這點是真要作驗證了,是真 power down mode(on->off)或擬 power down mode(keep rtc memory)。但無論如何就是 power down mode。
  • 不過,是筆者誤解了影片的闡述的意思了。也就是上一點陳述是錯的。簡單講,power down 就是 power down,是真 power down mode(on -> off)。文中很單純的一個額外用意是,利用 deep sleep,讓若 button 持續按下時,能仍處於 power down mode。僅僅就是這樣而已。
  • 故讓我們從頭開始。
  • 先說,我們可以實現單鍵啟閉 ESP 的功能,這也可能就是官方的原意:
  • EN 接至有 external pull-high 的 button,
  • 當按下 button,ESP 將啟動,隨即使用軟體將接至 EN 的另一根 GPIO X 拉 high。
  • 故我們將可在任何時候將 X 拉 low 關掉 ESP。
  • 這根 X 本身是 external pull-low 的,這意謂著當 power down 後會保持在 power down 下。
  • 但以上跟 deep sleep mode 有什麼關係?
  • 若 X 是 GPIO16,那麼除了不用外部 pull-low 外,下達 DeepSleep(),會使得 GPIO16/RST 處於 high,但共接的 EN 卻也處於 high。故勢必,GPIO16 須獨立於 power down mode。
  • 那麼,如何處理影片中說的試圖的解法,簡單,make code 不動作,唯當 break code,再拉 low,就能成就影片的功能「筆者後補註:毌需額外作為,即影片中的顧慮是多餘的。」。故至此,我們僅完成了 power down mode 的實作。還沒沾上 deep sleep 的邊。不過要記得,使用單鍵啟閉 ESP,將有至少 5uA 的功耗於關閉態,若有顧忌,只剩使用固鎖開關一途而非按鍵了。
  • 再說 deep sleep,如何對我們的實作品有助益,當不論 RTC 時?
  • 似乎沒了。
  • 不過讓我們試想這樣的狀況,充其量,就是讓 power down mode 和 deep sleep mode 能合用。何意?
  • 除了按鍵啟閉外,ON 時閒置一段時間,將進入 deep sleep mode(或直接關閉),很合理。此時,同一按鍵將再司喚醒的功能。故此時就須考量線路如何連接了。
  • 但問題是按鍵 make code 是 high 的,如何讓 reset 有個 low pulse?對筆者而言是無解的XD
  • 除非有按鍵設計是 abcd 4 pins,當 break code,cd 連接否則斷路,當 make code,ab 連接否則斷路。或許便能設計成 pull-high pull-low 兩路再進一步處理出 low pulse。
  • 故結論是 power down mode 和 deep sleep mode 對筆者而言合用上是無能為力的。
  • 最後,再看回 deep sleep,設 0 時,須外部的 low pulse 來喚醒。非 0 則由 RTC timeout 及 GPIO16 來喚醒。網上資料也提到了利用計數或浮點數來達到長時間睡眠。不過筆者對浮點數存疑因可能,RTC 只能單純的作正整數遞減。任何非正整數都將 bit-wise 對應地轉為正整數。
  • 最後一個問題也是網上未解之謎,GPIO16 如何能 reset 乾淨 RST pin?筆者的觀點是,RST 必然是被 pull-high 10K 的。若 reset 真失敗,變更加大 RST pull-high 電阻使得 GPIO16 low 分壓準位真小於規範的 low 準位並且 RST high 時可正常啟動,需踹。
  • 再看,GPIO2 是被 internal pull-high 的,但,是硬體預設或軟體初始化動作,需要踹看看。若前者,那麼我們毌需對 GPIO2 作任何動作它就已可以當成前述的 GPIO X。若是後者,那麼就 GPIO X 而言,遲至 user code 再將其設為 high(我們不再說拉 high,而是說設定成 pull-high/所有 GPIO 都有 internal pull-high 電阻),是有效的否則 power down mode 根本不可行。以上意謂著,GPIO2 不僅充份可當 GPIO X,尚可充當按鍵的 sensing pin。 當進入 user code 後,將其設為 input 用以 sensing 按鍵,而它的 internal pull-high 屬性從未改變,當然,需踹。至於前述 GPIO X 需外部 pull low;於此並不抵觸;EN 是純 input pin,具 high impedance 而抗干擾。故最終只需用掉一支腳位來實現按鍵啟閉的功能;active 下當按鍵再次按下時,設為 output 並拉 low,ESP 將被自己斷得乾乾淨淨的。「20210425 修正:GPIO X 設為 internal pull high 及 input 時,按鍵在前面已經定義成按下拉 high,所以根本沒有 low 的情況可被 sensing。因此在沒有更好的解法前,我們將只能視 GPIO X 為 output pin 用以將 EN 保持著 high 及拉 low,並且有另一根 GPIO Y,pull-low,input,並接至按鍵來 sensing 按下的情況。」。
  • 再談到另一未解之謎,有 reset 按兩次才能從 deep sleep 回來的 issue,猜測與 power sequence 或 clock 有關;cpu,rtc,flash。尋有解再來補充。

Categories: Arduino

Tags:

PHP Code Snippets Powered By : XYZScripts.com