IOT123 - D1M BLOCK - SLOG Assembly

513

9

Published

Introduction: IOT123 - D1M BLOCK - SLOG Assembly

About: The tension between novelty and familiarity...

D1M BLOCKS add tactile cases, labels, polarity guides and breakouts for the popular Wemos D1 Mini SOC/Shields/Clones.

Like a lot of micro-controllers, the Wemos D1 Mini has software and hardware watchdogs. There are several (not unusual) conditions where neither of these are effective and the micro-controllers can effectively stall. Also the Wemos D1 Mini also has an energy saving mode called deep sleep, but it requires hardware pins to be setup (RST connected to D0) in order to work.

This shield (SLeep + watchdOG) provides an easy way to setup deep sleep or use an external hardware watchdog.

I did proof-of-concepts using a 555 timer, a 74HC4060 binary counter and a great ATTiny85 external long watchdog timer (David Zimmer). The layouts were too complex for the limited real estate, once the jumpers for the deep sleep were also included. So using a lot of Davids concepts (he pats dogs which I continued) I created an Attiny85 I2C variety of the watchdog.

The messages the Master (Wemos D1 Mini or other MCU) can send to the SLOG are Enable, Disable, Pat (notify that a reset is not needed), Address (set the I2C Address to EEPROM on the Attiny), Interval (set the interval seconds the watchdog must be patted in, to EEPROM on the Attiny), Get Address (gets the current I2C Address), and Get Interval (gets the current Interval seconds).

If the master does not Pat the watchdog within the required Interval, it causes a reset of the MCU.

Step 1: Material and Tools

    There is now a full Bill of Materials and Sources list.

    1. The Wemos D1 Mini Protoboard shield and long pin female headers
    2. 3D printed Base and Lid, and labels for the D1M SLOG
    3. A set of D1M BLOCK - Install Jigs
    4. Hot glue gun and hot glue sticks
    5. Strong Cyanoachrylate Adhesive (preferably brush on)
    6. 1off ATTINY85 20PU
    7. 1 off 1N4001 diode
    8. 2 off 3P male headers
    9. 1 off 2P female header
    10. 2 off 2.54mm pitch Jumpers
    11. Hookup wire
    12. Soldering Iron and solder

    Step 2: Uploading the Sketch to the Attiny85

    An explanation of using an Arduino to upload onto the ATtiny85 is here.

    1. Ensure you can load sketches on your ATtiny85.
    2. Install the library TinyWireS on your system. Ensure the root of the zip file is at the level that includes the examples folder.
    3. Use the embedded code, and compile/upload onto the ATtiny.

    A stand-alone hardware watchdog with I2C comms, suitable as a shield (2.7 - 5.5V VCC) for Wemos D1 Mini, Arduino Uno...

    #include"TinyWireS.h"//SDA/SCL PB0/PB2 5/7 //tws_delay(ms)
    #include<EEPROM.h>
    #definePIN_BITE3
    #definePIN_LED1
    #defineBLINK_SHORT250
    #defineBLINK_LONG1000
    #defineEEPROM_VERSION0
    byte _i2cSlaveAddress = 8; // valid (verified) values 8 to 25
    byte _interval = 20;
    bool _enabled = true;
    unsignedlong _startTime;
    unsignedlong _elapsedTime;
    char _i2cCmd = '';
    byte _i2cParam = 0;
    voidsetup() {
    getFromEeprom();
    pinMode(PIN_BITE, OUTPUT);
    digitalWrite(PIN_BITE, HIGH); //avoid reset
    pinMode(PIN_LED, OUTPUT);
    digitalWrite(PIN_LED, LOW);
    TinyWireS.begin(_i2cSlaveAddress);
    TinyWireS.onReceive(receiveEvent);
    TinyWireS.onRequest(requestEvent);
    tws_delay(2000);
    }
    voidloop() { // no delay in loop - TinyWireS sonstraint
    digitalWrite(PIN_LED, LOW);
    int delay = 1000;// 1 second
    digitalWrite(PIN_BITE, HIGH); //avoid reset
    if (_enabled){
    _elapsedTime = millis() - _startTime;
    if (_elapsedTime > (_interval * 1000)){
    digitalWrite(PIN_BITE, LOW);
    _startTime = millis();
    digitalWrite(PIN_LED, HIGH);
    }
    }
    TinyWireS_stop_check;
    tws_delay(delay);
    }
    voidrequestEvent()
    {
    TinyWireS.send(_i2cParam);
    }
    voidreceiveEvent(uint8_t howMany) {
    char c='';
    while (1< TinyWireS.available()) { // loop through all but the last
    c = TinyWireS.receive(); // receive byte as a character
    }
    byte x = TinyWireS.receive(); // receive byte as an integer
    _i2cCmd = c;
    _i2cParam = x;
    switch (_i2cCmd) {
    case'E': // ENABLE
    _i2cParam = 1;
    _enabled = true;
    break;
    case'D': // DISABLE
    _i2cParam = 1;
    _enabled = false;
    break;
    case'P': // PAT
    _i2cParam = 1;
    _startTime = millis();
    blinkFor(BLINK_SHORT);
    break;
    case'G':
    // param stays the same
    // param is index of getters
    switch (_i2cParam){
    case0:
    _i2cParam = _i2cSlaveAddress;
    break;
    case1:
    _i2cParam = _interval;
    break;
    }
    break;
    case'A': // ADDRESS I2C FOR EEPROM
    // param is value
    _i2cSlaveAddress = _i2cParam;
    _i2cParam = _i2cSlaveAddress;
    EEPROM.update(0, _i2cSlaveAddress);
    break;
    case'I': // INTERVAL FOR EEPROM
    // param is value
    _interval = _i2cParam;
    _i2cParam = _interval;
    EEPROM.update(1, _interval);
    break;
    }
    }
    voidgetFromEeprom(){
    // Writing default configuration in EEPROM
    if(
    EEPROM.read(3) != 'S' ||
    EEPROM.read(4) != '+' ||
    EEPROM.read(5) != 'W' ||
    EEPROM.read(6) != EEPROM_VERSION
    ) EEPROM_write_default_configuration();
    EEPROM_read_configuration();
    }
    voidEEPROM_write_default_configuration(){
    // I2C ADDRESS
    EEPROM.update(0, _i2cSlaveAddress);
    // INTERVAL
    EEPROM.update(1, _interval);
    // VERSION
    EEPROM.update(2, EEPROM_VERSION);
    // Signature footprint
    EEPROM.update(3, 'S');
    EEPROM.update(4, '+');
    EEPROM.update(5, 'W');
    EEPROM.update(6, EEPROM_VERSION);
    }
    voidEEPROM_read_configuration(){
    _i2cSlaveAddress = EEPROM.read(0);
    _i2cCmd = _i2cSlaveAddress;// forces set of variable??
    _interval = EEPROM.read(1);
    _i2cCmd = _interval;// forces set of variable??
    }
    voidblinkFor(unsignedint x){
    digitalWrite(PIN_LED, HIGH);
    delay(x);
    digitalWrite(PIN_LED, LOW);
    }

    Step 3: Soldering the Header Pins (using the PIN JIG)

    There is a video above that runs through the solder process for the PIN JIG.

    1. Feed the header pins through bottom of the board (TX right-left) and into the solder jig.
    2. Press the pins down onto a hard flat surface.
    3. Press the board down firmly onto the jig.
    4. Solder the 4 corner pins.Reheat and re position board/pins if needed (board or pins not aligned or plumb).
    5. Solder the rest of the pins

    Step 4: Soldering the Other Components

    The 2P female header will be ~2mm too long. Carefully remove pins, file 1mm from both ends of plastic and replace pins. This component is to add a temporary LED to the SLOG whilst debugging (1 short blink for a Pat, 1 long blink for a reset). It is optional; if not including skip this and the wires that connect to it (the ground will till need to go to the ATTINY85).

    1. Place and solder ATTINY85 to shield, taking note of circle marker position
    2. Place and solder 2 off 3P male headers
    3. Place and solder 2P female header
    4. Place and solder 1N4001 diode taking note of polarity stripe
    5. Place ground hookup wire through holes and soldered to #4 & #13.
    6. Place hookup wire between D2 & #5 and solder
    7. Place hookup wire between #6 & #17 and solder
    8. Place hookup wire between D1 & #7 and solder
    9. Place hookup wire between #8 & #15 and solder
    10. Place hookup wire through 3V3 and solder on other side; solder other end to #16
    11. Place hookup wire through D0 and solder on other side; solder other end to #11
    12. Place hookup wire through RST and solder on other side; solder other end to #12
    13. Remove plastic collars from P3 male headers
    14. Cut P3 male headers pins down level with other pins.

    Step 5: Gluing the Component to the Base

    Not covered in the video, but recommended: put a large dob of hot glue in the empty base before quickly inserting board and aligning - this will create compression keys on either side of the board.

    1. With the base casing bottom surface ponting down, place the soldered assembly plastic header through the holes in the base; the (TX pin will be on side with the central groove).
    2. Place the hot glue jig under the base with the plastic headers placed through its grooves.
    3. Sit the hot glue jig on a firm flat surface and carefully push the PCB down until the plastic headers hit the surface; this should have the pins positioned correctly.
    4. When using the hot glue keep it away from the header pins and at least 2mm from where the lid will be positioned.
    5. Apply glue to all 4 corners of the PCB ensuring contact with the base walls; allow seepage to both sides of the PCB if possible.
    6. On some PCBs where the board ends close to the pins, dob a large amount of glue onto the base to the height of the PCB; when this cools apply more glue on the top of the PCB bridging to the lower glue.

    Step 6: Gluing the Lid to the Base

    1. Ensure the pins are free of glue and the top 2mm of the base is free of hot glue.
    2. Pre-fit the lid (dry run) making sure no print artifacts are in the way.
    3. Take appropriate precautions when using the Cyanoachrylate adhesive.
    4. Apply Cyanoachrylate to the bottom corners of the lid ensuring coverage of the adjacent ridge.
    5. Quickly fit the lid to the base; clamping shut the corners if possible.
    6. After the lid is dry, manually bend each pin so it is central in the void if necessary.

    Step 7: Adding the Adhesive Labels

    1. Apply pinout label on underside of base, with RST pin on side with groove.
    2. Apply identifier label on flat non-grooved side, with the pins void being the top of the label.
    3. Press labels down firmly, with a flat tool if needed.

    Step 8: Testing the Deep Sleep

    1. Upload this included sketch onto the D1M WIFI BLOCK (or Wemos D1 Mini SOC)
    2. Disconnect USB/D1M WIFI from PC
    3. Connect D1M SLOG to D1M WIFI.
    4. Ensure both jumpers are set to the outer position
    5. Connect USB/D1M WIFI to PC
    6. Show console window for correct COM port.
    7. Ensure 115200 baud rate selected.
    8. Verify only 3 lines from Loop printed, then sleep for 10 seconds then wake, repeat...

    A simple sketch to test the D1M SLOG (SLeep + watchdOG) deep sleep function. Ensure both jumpers are set to the outer position (connecting D0 to RST).

    // during wake prints 3 lines to console only
    // then sleep 10 seconds, then repeat...
    constint sleepSeconds = 10;
    voidsetup() {
    Serial.begin(115200);
    Serial.println("\n\nWake up");
    // Connect D0 to RST to wake up
    pinMode(D0, WAKEUP_PULLUP);
    }
    voidloop() {
    Serial.println("loop point 1");
    delay(1000);
    Serial.println("loop point 2");
    delay(1000);
    Serial.println("loop point 3");
    delay(1000);
    Serial.printf("Sleep for %d seconds\n\n", sleepSeconds);
    // convert to microseconds
    ESP.deepSleep(sleepSeconds * 1000000);
    }

    Step 9: Testing the External Hardware Watchdog

    This sketch depends on the Wire library; it should be installed with Arduino IDE.

    1. Upload this included sketch onto the D1M WIFI BLOCK (or Wemos D1 Mini SOC)
    2. Disconnect USB/D1M WIFI from PC
    3. Connect D1M SLOG to D1M WIFI.Ensure both jumpers are set to the inner position
    4. Connect a temporary blue LED (no resistor required) into the 2P Female header, with the +ve (long lead) to the outside of the casing. When the dog is patted a short blink occurs; on reboot a long blink occurs.
    5. Connect USB/D1M WIFI to PC
    6. Show console window for correct COM port.
    7. Ensure 9600 baud rate selected.
    8. Verify only the dog is patted 3 times, then the D1M WIFI BLOCK reboots.

    A test harness, using an UNO/ESP8266, for the ATtiny85 hardware watchdog, targeting D1M Blocks (custom shields for Wermos D1 Mini)

    #include<Wire.h>
    byte _interval = 0;
    voidsetup() {
    Serial.begin(9600);
    Wire.begin(); // join i2c bus (address optional for master)
    delay(3000);
    Serial.println("Sending started");
    SendCmd('G', 1); // get the expected pat interval
    Serial.print("The Interval on the ATTINY85 is ");
    Serial.print(_interval);
    Serial.println( " seconds");
    }
    byte x = 1;
    voidloop() {
    if (x < 5){
    Serial.print("Patting the dog #");
    Serial.println(x);
    SendCmd('P', 0);
    }else{
    Serial.println("Stopped patting the dog, expect a reset");
    }
    x++;
    delay(10000);
    }
    voidSendCmd(char cmd, byte par) {
    Wire.beginTransmission(8); // transmit to device #25
    Wire.write(cmd); // sends a char
    Wire.write(par); // sends one byte
    Wire.endTransmission();
    if (cmd == 'G'){// we are only getting Interval
    Wire.requestFrom(8,1); // request a single byte from slave device #25
    while(Wire.available()) // slave may send less than requested
    {
    _interval = Wire.read(); // receive a byte as character
    }
    }
    Serial.print(String(cmd) + " : ");
    Serial.println(par);
    }

    Step 10: Configuring the Shield From Within Your Sketch

    The bare minimum to use the external hardware watchdog in your sketch:

    1. Setup the D1M WIFI BLOCK as a I2C master (line #4)
    2. Write to the slave (D1M SLOG using its I2C Address line #8) within a repetitive time frame (defaults to 20 seconds), sending a char 'P' (line #9) and any byte value (line #10).

    If the MCU does not or can't pat the dog, it bites the master (resets).

    The bare minimim needed to pat the dog to stop a reset. If the MCU does not do its job it is bitten (reset).

    #include<Wire.h>
    voidsetup() {
    Wire.begin(); // join i2c bus (address optional for master)
    }
    voidloop() {
    Wire.beginTransmission(8); // transmit to device #8
    Wire.write('P'); // sends a char
    Wire.write(0); // sends one byte
    Wire.endTransmission();
    delay(10000);
    }

    Step 11: Configuring Your Shield Via Console Input

    The actions that can be configured via I2C are:

    1. Enable the watchdog (it looks for pats, and can bite if no pat in time)
      cmd: 'E'
      param: 0
    2. Disable (no patting required)
      cmd: 'D'
      param: 0
    3. Pat (broadcasts the master is alive
      cmd: 'P'
      param: 0
    4. Get the slave I2C Address (needs to know this anyhow - may be useful when many actions have taken place)
      cmd: 'G'
      param: 0
    5. Get the Interval is seconds
      cmd: 'G'
      param: 1
    6. Set the I2C Address
      cmd: 'A'
      param: valid (verified) values 8 to 25
    7. Set the Interval
      cmd: 'I'
      param: valid values 0 to 255

    To send these commands to the D1M SLOG:

    1. Upload this included sketch onto the D1M WIFI BLOCK (or Wemos D1 Mini SOC) ensuring the slave address is correct.
    2. Disconnect USB/D1M WIFI from PC
    3. Connect D1M SLOG to D1M WIFI.
    4. Ensure both jumpers are set to the inner position
    5. Connect a temporary blue LED (no resistor required) into the 2P Female header, with the +ve (long lead) to the outside of the casing.
    6. When the dog is patted a short blink occurs; on reboot a long blink occurs.
    7. Connect USB/D1M WIFI to PC
    8. Show console window for correct COM port.Ensure 9600 baud rate selected.
    9. Set line ending to newline (lower RHS combo box)
    10. Input the above commands/paras followed by an
    11. If the param is 0 (zero) it can be omitted, so valid inputs are E (may cause resets), D, P, G0, G1, A9, I40
    12. Only I2C Slave Address and Interval ar persisted to EEPROM.

    Use serial input (console) to send I2C commands to an I2C slave. Must accept the format (2 bytes of data).

    #include<Wire.h>
    const byte _numChars = 32;
    char _receivedChars[_numChars]; // an array to store the received data
    boolean _newData = false;
    voidsetup() {
    Serial.begin(9600);
    Wire.begin(); // join i2c bus (address optional for master)
    delay(2000);
    Serial.println("D1M WIFI BLOCK is ready - you can cofigure you I2C D1M Shield from here!");
    Serial.println("");
    Serial.println("Set line ending to newline (lower RHS combo box)");
    Serial.println("");
    Serial.println("The format of commands are:");
    Serial.println("\t");
    Serial.println("\tEverything after the first character will attempt to convert to a byte value");
    Serial.println("\tIf only one character is entered or the characters cannot be coerced to a byte, 0 will be sent as the byte param");
    Serial.println("");
    sendCmd('D', 0); // disable watchdog so it does not reset - the user can input E (to re-enable)
    }
    voidloop() {
    recvWithEndMarker();
    parseSendCommands();
    }
    voidrecvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    while (Serial.available() >0 && _newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
    _receivedChars[ndx] = rc;
    ndx++;
    if (ndx >= _numChars) {
    ndx = _numChars - 1;
    }
    } else {
    _receivedChars[ndx] = '\0'; // terminate the string
    ndx = 0;
    _newData = true;
    }
    }
    }
    voidparseSendCommands() {
    if (_newData == true) {
    char c = _receivedChars[0];
    byte b = 0;
    if (strlen (_receivedChars) >1){
    char* numberPart = _receivedChars + 1;
    b = atoi(numberPart);
    }
    sendCmd(c, b);
    _newData = false;
    }
    }
    voidsendCmd(char cmd, byte par) {
    Wire.beginTransmission(8); // transmit to device #8
    Wire.write(cmd); // sends a char
    Wire.write(par); // sends one byte
    Wire.endTransmission();
    byte response = 0;
    bool hadResponse = false;
    if (cmd == 'G'){
    Wire.requestFrom(8,1); // request a single byte from slave device #25
    while(Wire.available()) // slave may send less than requested
    {
    hadResponse = true;
    response = Wire.read(); // receive a byte as character
    }
    }
    Serial.println("Sending command:");
    Serial.println("\t" + String(cmd) + " : " + String(par));
    if (cmd == 'G'){
    if (hadResponse){
    Serial.println("Getting response:");
    Serial.println("\t" + String(response));
    }else{
    Serial.println("No response, check the address/connection");
    }
    }
    }

    Step 12: Next Steps

    1. Program your D1M BLOCK with D1M BLOCKLY
    2. Check out Thingiverse
    3. Ask a question at the ESP8266 Community Forum

    Share

      Recommendations

      • Oil Contest

        Oil Contest
      • Water Contest

        Water Contest
      • Creative Misuse Contest

        Creative Misuse Contest

      Discussions