AT - Wifi - ESP8266

Posted on
  • Some irregular behavior: why can it not find the "AT" module (anymore) and gets (completely) lost - even though the submit to the board made no complaint what so ever...

     _____                 _
    |   __|___ ___ ___ _ _|_|___ ___
    |   __|_ -| . |  _| | | |   | . |
    |_____|___|  _|_| |___|_|_|_|___|
              |_| http://espruino.com
     1v81 Copyright 2015 G.Williams
    >echo(0);
    =undefined
    >onInit();
    =undefined
    is[0]Seq: ok
    is[1]DSP: ok
    ERROR: SD card must be setup with E.connectSDCard first
    WARNING: Module "AT" not found
    Uncaught Error: Field or method "connect" does not already exist, and can't create it on undefined
     at line 1 col 22
    {l.at=g=require("AT").connect(a);require­("NetworkJS").create...
                         ^
    in function "connect" called from line 6 col 4
      }); }
       ^
    

    No matter how many times I retry initialization, still cannot find the "AT" module.

    Resending the software helps to get over 'missing "AT" module' but gets stuck and keeps showing this:

    |   __|___ ___ ___ _ _|_|___ ___
    |   __|_ -| . |  _| | | |   | . |
    |_____|___|  _|_| |___|_|_|_|___|
              |_| http://espruino.com
     1v81 Copyright 2015 G.Williams
    >echo(0);
    =undefined
    >onInit()
    =undefined
    is[0]Seq: ok
    is[1]wifi.reset: No 'ready' after AT+RST: failed
    >
    Disconnected
    > 
    

    Disconnected means: power off... not very helpful...

    I triet to power cycle just ESP8266, but noticed a different special effect: even though having a 4.7uF capacitor across the ESP8266 ground and power pins, the ESP8266 shocks Espruino on a regular base into 'reset' by short power fail...

    Adding an additional 10uF capacitor maes it possible to power cycle ESP8266 without 'resetting' Espruino.

    But it is not all that reliable: power cycle bot at the same time creates some timing issues and makes ESP8266 mess with Espruino so badly, that the IDE - though saying connected - cannot or does not upload code...

    It let me conclude that some ESP8266s are better than average working behavior, and more are worse.

    The complete code is shown in the next post. The code has some nice layering features:

    1. Separation of configuration and module loading from (re)initializing
    2. initialization/callback helper
    3. sequencer/callback helper

    Separation of configuration and module lodading defines clearly what is code-upload and what is going on on onInit(), especially after save() and re-powering.

    Since all things work event driven with simple to complex, nested callbacks, I built the two helpers that deal with the callback maze, especially when:

    1. Multiple devices are involved - for example: ILI9341 or a-like controlled displays, serially connected ESP8266, serially connected sensors,...

    2. Sequence of calls to one and the same device have to be serialized the way that the next call has to wait until the callback of the previous one has 'finished' - for example: get version info, access point, and IP address from ESP8266 and display them, all bundled in a function.

    So much so far about the sequencer (gSeq - g(lobal variable for) Seq(uencer) for commands.

    Starting with the command:

    1. Each command is a function that accepts a callback function from the sequencer on invocation and executes that callback function at last (after completion). The inovcaton makes the sequencer handle the next command in sequence.

    2. It is a FIFO - commands/functions added first is executed first - which needs not much explaining: a new command goes on the top of a pile and command by command is pulled from the bottom of the pile until pile is gone.

    3. It is a LIFO - commands/functions that have to be executed right after a result comes back BUT or AND before the next command waiting in FIFO - which needs a bit more explaining:

    If such a command returns the result it - logically - may need to be callback-style processed before the next invocation happens, and can therefore be inserted at the bottom of the command pile.

    A picture of the hardware setup was already part of a separate post.

  • the ESP8266 shocks Espruino on a regular base into 'reset' by short power fail...

    That sounds like it could be a good thing to sort out - for Espruino to reset the voltage has to drop below 2v, so it looks like you have some pretty major power supply issues.

    Are you saying you've got the ILI9341 connected as well? It's possible that the backlight running off the 3.3v rail isn't helping.

    Which board are you using? The Pico, or Original Espruino? I don't think the original Espruino's voltage regulator is powerful enough to handle the peak power draw of the ESP8266 (it's rated at 150mA I think?). Ideally you'd add a second voltage regulator, but if not then go for big capacitors - like 100uF or so, and it might help you out. The 6v-rated caps are really quite small.

  • Code is also attached as file... ;-)

    // /ESP8266/server/MyPICOMon00R2.js
    
    var gIsL = true; // ...is logging
    var gIsC = true; // ...terminal is console vs. display
    var gLog = function(v) { console.log(v); };
    
    var gTrm = null, T_C = {w:240, h:320, lh:10}; // terminal config
    
    var gCtl = // initialization controller
    { is:[], i:-1 
    , adi: function(i) { this.is.push(i); }
    , ini: function(ok,str) { if (this.i >= 0) {
        if (gIsL) gLog("is["+this.i+"]"+((str)?str:"")+": "+((ok)?"ok":"failed")); } 
        if (ok) { if (++this.i < this.is.length) { var _t = this; 
          setTimeout(function(){ _t.is[_t.i](function(ok,txt){ _t.ini(ok,txt); }); },1); }  
                } else { /* is[i]() failed */ } }
    , run: function() { this.i = -1; this.ini(true); }
    };
    
    var gSeq = // sequence controller
    { fs:[], bsy:false, t:null
    , ini: function() { this.fs = []; this.bsy = false; }
    , ads: function(f,r,t) { this.fs.push([f,r,t]); 
        if (!this.bsy) { this.exe(); } }
    , exe: function() { if ((this.bsy = (this.fs.length > 0))) { 
        var s = this.fs.splice(0,1)[0];
        s[0](this.nex.bind(this)); } }
    , nex: function(f,r,t) { if (f) { this.fs.splice(0,0,[f,r,t]); }
        setTimeout(this.exe.bind(this),1); }
    }; gCtl.adi(function(cb){ gSeq.ini(); cb(true,"Seq"); });
    
    gTrm = // terminal
    { c:T_C 
    , cl: 0 
    , p: function(l,nl) { var c = this.c;
        if (gIsC) { gLog(l); return; } // terminal is console
        gD.setColor(0,0,0);
        if (this.cl + c.lh > c.h) {
          gD.fillRect(0,this.cl,c.lh,this.cl+c.lh-­3);
          this.cl = 0;
        }
        gD.fillRect(0,this.cl,c.w-1,this.cl+c.lh­-1);
        gD.setColor(1,1,1); gD.drawString(l,0,this.cl);
        if (nl) { this.cl += c.lh; }
        gD.setColor(0,0,0); gD.fillRect(0,this.cl,c.w-1,this.cl+c.lh­-1);
        gD.setColor(1,0,0); gD.fillRect(0,this.cl,c.lh,this.cl+c.lh-­3);
      } 
    };
    
    /* disabling display for test without display
    var gD = null, DSP_C = // display
    { md:require("ILI9341")
    , spi:SPI1
    , spiC: {sck:A5, miso:A6, mosi:A7, baud:1000000}
    , dc:B10, cs:B1, rst:B13
    };
     */
    
    var gW = null, WIFI_C = // wifi config
    { md:require("ESP8266WiFi_0v25")
    , ser:Serial2, bd:115200, serC:{tx:A2, rx:A3}
    , ssid:"myWLAN", lak:"myCredential" 
    , ip:"", p:80 
    };
    
    var http = null, HTTP_C = // http configs / requests
    { md:require("http") 
    , urls:
      [ "http://www.pur3.co.uk/hello.txt"
      , "http://weather.noaa.gov/pub/data/foreca­sts/marine/coastal/pz/pzz535.txt"
      , "http://192.168.0.103/esp/json.jsn"
      , "http://l92.168.0.103:1337/"
      ]
    };
    
    /* disabling display for test without display
    gCtl.adi(function(cb){ var c = DSP_C; // display initialization
      c.spi.setup(c.spiC);
      gD = c.md.connect(c.spi, c.dc, c.cs, c.rst, function(){ 
        gD.clear();
        cb(true,"DSP");
      }); }
    );
     */
    
    gCtl.adi(function(cb){ var c = WIFI_C; // wifi multi level initialization
      c.ser.setup(c.bd, c.serC);
      gW = c.md.connect(c.ser, function(err){
        if (err) { cb(false,"wifi.reset: " + err); }
        else { cb(true,"wifi.reset"); }
      }); }
    );
    gCtl.adi(function(cb){ var c = WIFI_C;
      gW.connect(c.ssid, c.lak, function(err){
        if (err) { cb(false,"wifi.connect: " + err); }
        else { cb(true,"wifi.connect"); }
      }); }
    );
    
    // get url content and display raw in console
    function getc(udx,nex) { var c = HTTP_C;
      if (gIsL) gLog(c.urls[udx] + ":");
      c.md.get(c.urls[udx], function(res){
        res.on('data', function(dta){
          gLog(dta);
          if (nex) nex();
        });
      });
    }
    
    // get url content and and show in display
    function getd(udx) { var c = HTTP_C;
      gLog("---> " + c.urls[udx] + ":");
      var d = true, l = "", ol, nl;
      c.md.get(c.urls[udx], function(res){
        res.on('data', function(dta){
          l = l + dta;
          var ls = l.split("\n"), lm = ls.length - 1, lx = -1;
          while (++lx < lm) { ol = (l = ls[lx]).length;
            if ((d = d && (l != "$$"))) {
              while (ol > (nl = (l = l.replace(" OR LESS","|<")).length)) ol = nl; 
              while (ol > (nl = (l = l.replace(" TO ","~")).length)) ol = nl; 
              while (ol > (nl = (l = l.replace(" TO","~")).length)) ol = nl; 
              gTrm.p(l,true);
            } }
          l = ls[lm]; ls = null; 
        });
      });
    }
    
    // get info - time (from node server), ESP9266 version, IP, and access point
    function getInfo() {
      // gSeq.ads(function(nex){ getc(2,nex); });
      gSeq.ads(function(nex){
        gW.getVersion(function(e,v){
          if (e) { gTrm.p("get Version failed: " + e,true); }
          else { gTrm.p("Version: " + v,true); }
          nex();  
      }); });
      gSeq.ads(function(nex){
        gW.getIP(function(e,ip){
          if (e) { gTrm.p("get IP failed: " + e,true); }
          else { gTrm.p("IP: " + ip,true); }
          nex();  
      }); });
      gSeq.ads(function(nex){
        gW.getConnectedAP(function(e,ap){
          if (e) { gTrm.p("get AP failed: " + e,true); }
          else { gTrm.p("AP: " + ap,true); }
          nex();
      }); });
    }
    
    // start after upload by invocation in console or
    // start after save and re-powering
    function onInit() { gCtl.run(); }
    

    1 Attachment

  • ...100uF... display brightness was actually 'fluctuating'... ESP8266 is fed by PICO's 3.3 regulator, PICO fed by regular USB, display fed from PICO Bat (5-diode)V.

    Should the extra 100uF go before or after the 3.3V regulator?

    With this high capacity initialization may need to run a delay... also controllable very easily with the intializer and sequencer... something left to do,

  • display brightness was actually 'fluctuating'

    Wow, yeah - so something's going wrong.

    It turns out the rev 1v3 picos don't actually have a very good diode in them. It's fine normally, but if the Pico ever did get shorted out for a fraction of a second the diode could have gone slightly open circuit? One way to check that would be to put an oscillocope on the 5V pin and see if that fluctuates much.

    If that's the problem it's easy enough to replace the diode though...

    Not sure I understand about where the 100uF cap should go? Just put it right across the ESP8266 - I'd try that before adding a new regulator (as the Pico's one is good enough to handle the ESP8266)

  • By the way, why doesn't the ESP8266 module have a disconnect-from-access-point (AT+CWQAP) function?

  • I think because nobody has really requested it. It'd be easy enough to add though.

    Generally if you're disconnecting to save power, you'd just use CH_PD to power the whole module down?

  • I missed a disconnect function when testing connect-on-demand code. I haven't got as far as saving power, but that will become a very important topic. On a battery operated device, I want the battery to last long, but I also want it to be ready quickly. After powering up, it takes a few seconds to initialize and then connect to an AP. I'm not sure if there's a power-efficient way to keep it on standby...

  • @Dennis.... expected a disconnect as well... but if the CH_PD does kind of the same plus even more, it might be worth to sacrifice a pin to control that... from a 'comprehensive' software point of view a disconnect makes sense though... it could even be tied to a pin when passed on that pin on initialization ;-)... now I'm getting ahead of...

    Furthermore - if it is easy to add 'custom' commands to wifi wrapping AT wrapping device, adding an at(atString, callback) could be the solution. The method would include the setup of the context and abstract callback handling. This method would Drawing a line for a standard what is included and what is not is a gray zone.

  • adding an at(atString, callback) could be the solution

    Literally just:

    wifi.disconnect = function(callback) { this.at.cmd("AT+CWQAP\r\n",1000,callback­); };
    

    would do it I think.

  • That's the disconnect code I'm using. I'm also using AT+GSLP=3600000 to put the ESP8266 into deep sleep, then using RST pin to wake it up again. I still have to actually measure current to see if this is working as I'm not entirely convinced.

    I'm going to experiment with using CH_PD pin also once I get my non-Huzzah ESP8266s in from China.

  • Ok, great! So it does work ok? That'd be nice and easy to add to the existing drivers.

  • Yes, it works as in it is no longer connected, but I still need to measure power draw.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

AT - Wifi - ESP8266

Posted by Avatar for allObjects @allObjects

Actions