SPI connection after power down mode

Hello everybody,

I use a Nodemcu as SPI Master to request data (integer value) from an Arduino Nano (SPI slave).

In order to save power consumption I set the Nano in powerDown mode and put the Nodemcu in reset mode. Every x seconds the Nodemcu wakes up and pulls a digital pin too high that triggers an interrupt at the Nano to wake it up. After a short delay I request the data via SPI.

The communication works very good as long as I do not set the Nano into powerDown mode.
But if I am doing the Nano sends only garbage most of the time (a constant number).

I assume, that the Nano and the Nodemcu are out of sync after waking up.
Is there a way to re-sync them?

//#include <Wire.h>
#include "LowPower.h"
#include <SPI.h>

// Input Pins
const int WakeupPin_ESP8266   = 3;
const int RainCounterPin      = 2;

// Debug
#define LEDPin 5

// SPI connection
volatile byte command = 0;

// Rain counter variable
volatile unsigned int RainCounter = 0;
volatile unsigned long lastRainCount = 0;

// RainCounter
bool lastRainState = false;
unsigned long lastCount = 0;
const unsigned long T_debounce_ms = 10;

void setup() {
  Serial.begin(115200);
  Serial.println("Startup");

  // Interrupt (External from ESP8266)
  pinMode(WakeupPin_ESP8266, INPUT);
  pinMode(RainCounterPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(WakeupPin_ESP8266), Wakeup_ISR, RISING);
  attachInterrupt(digitalPinToInterrupt(RainCounterPin), Rain_ISR, RISING);

  // Debug
  pinMode(LEDPin,OUTPUT);
  digitalWrite(LEDPin,HIGH);

  // Setup SPI
  SPI_init();
}

void loop() {

  bool AllowSleepRC = false;
  bool RainState = digitalRead(RainCounterPin);
  if(RainState && !lastRainState && (millis()-lastCount)>T_debounce_ms)
  {
    // State changed to true
    // Count up
    lastCount = millis();
    RainCounter++;
    Serial.print("Rain Counter: ");Serial.println(RainCounter);    
  }
  lastRainState = RainState;
  
  if((millis()-lastCount)>T_debounce_ms && !RainState)
    AllowSleepRC = true;
    

  
  Serial.println(digitalRead(WakeupPin_ESP8266));
  bool AllowSleepWU = false;
  if (digitalRead(WakeupPin_ESP8266) == LOW)
  {
    AllowSleepWU = true;
  }

  if(AllowSleepWU && AllowSleepRC)
  {    
    digitalWrite(LEDPin,LOW);
    delay(10);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
//    SPI_init();
    digitalWrite(LEDPin,HIGH);
  }
    

}


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  cli();
  byte c = SPDR;

  if(c=='r')
  {
    SPDR = RainCounter;
  }

  sei();
}



void Wakeup_ISR()
{
}

void Rain_ISR()
{
}

void SPI_init()
{
  pinMode(MISO, OUTPUT);
  SPCR |= bit(SPE);         /* Enable SPI */
  SPCR |= bit(SPIE);
}

I would like to believe that you have areusing NodeMCU as SPI Master and the sketch you have posted is for the Master. If so, why --

MISO pin is configured as OUTPUT? Should it not be an INPUT line?

Moreover, where is the SS (Slave Select) line of Master? It must be asserted LOW to enable the SPI Port of the Slave.

Where is the SPI.begin() code for the Master to create/enable SPI Port?

Please, post the codes/sketch of NANO.

Hello Golam Mostafa,

thanks for your reply.

In fact this is the code of the Slave (Nano).
The Nano counts the impulses coming from a rain sensor and sends it to the master if requested.

The code in the main loop makes a debouncing of the digital input signal.

So, post the sketch that you have written for NodeMCU-Master.

This is the master code:

#include <Wire.h>
#include <BH1750.h>

// Wifi library
#include <ESP8266WiFi.h>

// SPI connection (to external Arduino)
#include <SPI.h>

// MQTT library
#include <PubSubClient.h>

// DHT22 sensor (temperature / humidity)
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

// Sensor settings
// Light sensor
BH1750 lightMeter(0x23);
float lux;

// Rain sensor
#define   RainSensorWakeupPin D1

// DHT22
#define DHTPIN D2     // Digital pin connected to the DHT sensor 
#define DHTTYPE    DHT22     // DHT 22 (AM2302)
DHT_Unified dht(DHTPIN, DHTTYPE);
float Temperature;
float Humidity;
bool failureTemperature     = false;
bool failureHumidity        = false;

// Wifi settings
char ssid[] = "Kabenja";   // your network SSID (name) 
char pass[] = "dmkblsmden5e95k";   // your network password
const char* mqtt_server = "192.168.178.25";

// MQTT variables
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

// MQTT topics
#define outTopicLux           "nodeMCU/WeatherStation/Lux"
#define outTopicTemperature   "nodeMCU/WeatherStation/Temp"
#define outTopicHumidity      "nodeMCU/WeatherStation/Humidity"
#define outTopicRain          "nodeMCU/WeatherStation/Rain"

void setup(){
  Serial.begin(115200);
  Serial.println("Setup");
  Serial.setTimeout(2000);

  // Wait for serial to initialize.
  while(!Serial) { }
  
  // DHT22 setup
  dht.begin();

  // Wakeup Pin for Rain Counter
  pinMode(RainSensorWakeupPin, OUTPUT);

  // SPI
//  pinMode(SS, OUTPUT);    // DEBUG
//  digitalWrite(SS, HIGH);  // ensure SS stays high for now
  SPI.begin ();

  // Slow down the master a bit
//  SPI.setClockDivider(SPI_CLOCK_DIV8);

 // setup_wifi();

//   Wifi Settings
  WiFi.mode(WIFI_STA);
  WiFi.hostname("ESP8266-WeatherStation");
   // Connect or reconnect to WiFi
  if(WiFi.status() != WL_CONNECTED){
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    while(WiFi.status() != WL_CONNECTED){
      WiFi.begin(ssid, pass);  // Connect to WPA/WPA2 network. Change this line if using open or WEP network
      Serial.print(".");
      delay(5000);
    }
    Serial.println("\nWifi Connected.");
  }

  
  // Initialize the I2C bus (BH1750 library doesn't do this automatically)
  Wire.begin(D4,D3);    // SDA , SCL
  // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3);


  // begin returns a boolean that can be used to detect setup problems.
  if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
//    Serial.println(F("BH1750 Advanced begin"));
  }
  else {
    Serial.println(F("Error initialising BH1750"));
  }


  // Setup MQTT
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {  
  // MQTT
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // Light measurement
  lux = lightMeter.readLightLevel();
  Serial.println("");
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lx");

  // Wakeup Rain Counter Atmel
  digitalWrite(RainSensorWakeupPin, HIGH);
  Serial.println("Wakeup Rain Counter");
  
  delay(50);
  // Receive data
  transferAndWait('r');
  delay(50);
  byte RainCounter = transferAndWait('a');
//  digitalWrite(SS, HIGH);
  Serial.print("Rain Counter: ");Serial.println(RainCounter);
//  delay(100);
 

  digitalWrite(RainSensorWakeupPin, LOW);
  dtostrf(RainCounter, 3, 0, msg);
  client.publish(outTopicRain, msg);

  // Read DHT22 (Temperature and Humidity)
  ReadTemperature();
  ReadHumidity();

  if(!failureTemperature)
  {
    char msg[50];
    dtostrf(Temperature, 3, 2, msg);
    client.publish(outTopicTemperature, msg);
    Serial.print("Msg: ");Serial.println(msg);
  }
  if(!failureHumidity)
  {
    char msg[50];
    dtostrf(Humidity, 3, 2, msg);
    client.publish(outTopicHumidity, msg);
  }
  
  char msg[50];
  dtostrf(lux, 3, 2, msg);
  client.publish(outTopicLux, msg);

  delay(120);
  ESP.deepSleep(5e6);
  delay(100);
  

}

// SPI transer and receive
byte transferAndWait (const byte what)
{
  byte a = SPI.transfer (what);
  delayMicroseconds (20);
  Serial.print("Received: ");Serial.println(a);
  return a;
} // end of transferAndWait


void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266-WeatherStation";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...    

      
      // ... and resubscribe
//      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void ReadTemperature()
{
  // Read temperature
  sensors_event_t event;
  dht.temperature().getEvent(&event);  
  if (isnan(event.temperature)) {
    Serial.println(F("Error reading temperature!"));
    failureTemperature = true;
  }
  else {
    failureTemperature      = false;
    Temperature             = event.temperature;
    Serial.print(F("Temperature: "));
    Serial.print(Temperature);
    Serial.println(F("°C"));
  }
}

void ReadHumidity()
{
  // Read humidity
  sensors_event_t event;
  dht.humidity().getEvent(&event);  
  if (isnan(event.relative_humidity)) {
    Serial.println(F("Error reading humidity!"));
    failureHumidity         = true;
  }
  else {
    failureHumidity       = false;
    Humidity              = event.relative_humidity;
    Serial.print(F("Humidity: "));
    Serial.print(Humidity);
    Serial.println(F("%"));
  }
}

Can you pass the SPI connection diagram between NANO and NodeMCU. I mean:

NANO (DPin-10, 11, 12, 13) -------> NodeMCU (what Pin)? Are they: CMD, SDI, SDO, CLK respectively?

I have this type of NodeMCU:

I use the same NodeMCU.
Here my connections (sorry for the bad drawing).

It is about a year that I have not done any project with my NodeMCU -- even I have forgotten which GPIO (2) is connected with the built-in LED near the MCU/WiFi Module of the Board. I have to first check that the Board is working. After a lot of search in the net and subsequent experiment, I have found the GPIO-2 (D4) which connects the LED. Anyway, the Board is working. There is another LED on my near the UART/USB converter chip -- do you know which GPIO-pin is connected with the LED?

Now, I am building your NodeMCU-NANO Project to look into the SPI problem in deepSleep/powerDown mode.

Try GPIO 16 to use it.