Is it possible to stop SPI bus and turn MISO, MOSI and SCK pins to INPUTS?

I am trying to get the power consumption of a board down low when mains/AC power supply fails and it has to fall back on battery power.

I am using a photon (now with 0.8.0-rc.4) and turn off all peripherals before calling System.sleep().

I have found that stopping the SPI bus and/or pinMode to INPUT for MOSI, MISO and SCK stops the sleep function from working reliably.

SPI.end();
pinMode(A3,     INPUT);             //to avoid push/pull turn all OUTPUTS to INPUTS
pinMode(A4,     INPUT);             //to avoid push/pull turn all OUTPUTS to INPUTS
pinMode(A5,     INPUT);             //to avoid push/pull turn all OUTPUTS to INPUTS

The problem I have if I do not turn these pins to INPUT is that there is a large parasitic current drawn through the photon. Any ideas how to stop the current loss without inhibiting System.sleep()?

What kind of sleep? Deep sleep does turn off the periferals and put the GPIOs into Hi-Z (apart from WKP).

But yes, you can use any of the GPIOs as INPUTs.
BTW, MISO/A4 already is set as INPUT in SPI mode.

@ScruffR - What kind of Sleep? - System.sleep(button1, RISING, sleepPeriod); Not deep sleep initially because I want to wake/resume processor operation if the mains power is restored - this is signalled by a short (50mS) pulse high on button1 and there is a timeout to wake after a couple of hours (backup battery life) and check if mains power still off then deep sleep.

MISO/A4 - sorry I didn’t make it clear I know it is set as INPUT, if I include pinMode(A4, INPUT) this stops it going into sleep also pinMode(A3, INPUT) and pinMode(A5, INPUT) and SPI.end().

This is rather frustrating because I can see on the current meter the value dip very briefly to 1mA and then it goes back to 11mA. The real problem is it not getting into sleep though.

I’d not see that as reason to rule out deep sleep. With a connection from button1 to WKP (or just use A7/WKP for button1 to start with) you can have both (obviously assuming you aren’t already using A7/WKP otherwise tho’)

Deep Sleep does a reset / restart of the application code at the end of the timeout period or on a pulse to WKP. I rather see Deep Sleep as a second stage of backup battery protection. The other issue with using WKP is that it is currently used as a PWM output so that would be a PCB layout change…

Sleep mode would be OK with the backup battery capacity if it reliably engaged - I still can’t get a setup which always works.

What type of device (Photon, P1, Electron, or E series)?

Photon

I’m not sure why you’re getting 11 mA. I tested with a Photon running 0.8.0-rc.4 using the code below and got 3.33 mA in stop mode sleep (pin + time).

Power was 5V on VIN from a bench power supply. There were no other connections.

#include "Particle.h"

void buttonHandler();

bool doSleep = false;


void setup() {
	Serial.begin(9600);
	System.on(button_click, buttonHandler);
}

void loop() {

	if (doSleep) {
		doSleep = false;
		System.sleep(WKP, RISING, 120);
	}
}

void buttonHandler() {
	doSleep = true;
}

I also tested SLEEP_MODE_DEEP, and that was 75.5 uA.

1 Like

The point about this thread was not the absolute power consumption/ current drawn. The photon is sat in a PCB (see photo) and because of push/pull on the photon pins (specifically the SPI bus) rather than getting 3.3mA, the best I can get is 11mA.

The issue is why Sleep is not engaged properly (current drawn is 95mA) when I set some pins to INPUT and also why this works sometimes and not others. Why does calling SPI.end() beforehand completely stop Sleep?

Oh, I see now. When you say that it fails to sleep, do you mean that it doesn’t actually stop, or that it’s using too much current. Does this happen all of the time or just occasionally?

I used this test circuit with an SD card adapter connected to SPI, but the power not connected, to simulate a situation where you’ve controlled the SD card by MOSFET and turned it off.

I got 2.82 mA in stop sleep mode. I entered sleep mode 10 times and got that consistently.

This is the code I used:

#include "Particle.h"

void buttonHandler();

bool doSleep = false;


void setup() {
	Serial.begin(9600);
	System.on(button_click, buttonHandler);

	SPI.begin(A2);

}

void loop() {

	if (doSleep) {
		doSleep = false;

		SPI.end();
		pinMode(A2, INPUT);
		pinMode(A3, INPUT);
		pinMode(A4, INPUT);
		pinMode(A5, INPUT);

		System.sleep(WKP, RISING, 120);
	}
}

void buttonHandler() {
	doSleep = true;
}

Tested with 0.8.0-rc.4.

I also tested it the other way, with 3V3 connected to the SD card reader and GND disconnected, like with an N-channel MOSFET. The current was actually a little higher, 3.2 mA, but still low.

1 Like

Sleep stops the loop, then the Application Watchdog will break it out and do a system restart, which because I save the run state of the device to eeprom it recovers this and sends the control back to the controller function for sleeping.

Clearly the reason that Sleep is not engaged always is due to something else than SPI.end() and pinMode() calls.

I am wondering if the fact I use WKP as a PWM Output to drive the TFT LEDs might be a reason?

Also, it is odd that the current draw is less at 2.82mA with the SD card reader than without?

There is a ticket open on this item that Dave is handling - I have sent a load of code snippets to see if there is anything that stands out in what I have done.

Yes, that’s weird. You’ve got me stumped. Hopefully Dave will find something.

I added PWM output on WKP:

#include "Particle.h"

void buttonHandler();

bool doSleep = false;


void setup() {
	Serial.begin(9600);
	System.on(button_click, buttonHandler);

	pinMode(WKP, OUTPUT);
	analogWrite(WKP, 128);

	SPI.begin(A2);

}

void loop() {

	if (doSleep) {
		doSleep = false;

		SPI.end();
		pinMode(A2, INPUT);
		pinMode(A3, INPUT);
		pinMode(A4, INPUT);
		pinMode(A5, INPUT);

		System.sleep(D6, RISING, 120);
	}
}

void buttonHandler() {
	doSleep = true;
}

And still got 2.84 mA.

The extra current with 3V3 going to the SD may be caused by a ground path through the SD via the STM32 GPIO pins. I had something similar happen on a microSD and found that low-side switching (disconnect GND) worked better than high-side (3V3) switching. In my situation, the Photon was deep sleeping.

@rickkas7 I have developed a sleep test application by branching and hacking down the current latest application version (I have left quite a bit of functionality in - but see later point). I built this and flashed to a photon in the same board. Using 0.7.0, if I include SPI.end() and the pinMode() changes for A3, A4 and A5 it does the same thing and will not go into proper sleep. If I comment these out then it is reliably going into and coming out of sleep [which is a result] and my current draw is 2.7mA. The reason for the difference with the 11mA I had seen before is that I had not attached a sensor which is attached to the on-board GPIO expander. The power supply to the sensor is switched off yet it is finding a path to draw 8mA through the GPIO expander and to the I2C lines on the photon! @peekay123 You were on the right tracks!

I am still at a lost to know exactly why with the original application build I am seeing the unreliable entry to Sleep. I will try adding back functionality until I break it. I will also try to see if SPI.end() works with 0.8.0-rc.4 but clearly this does not make much difference to the current consumption when in sleep.

@armor, just to be clear, which pin are you waking on (button1)? What is generating the “short 50ms” wakeup pulse?

D4 - is attached to the output of an OR gate with its inputs being the signal from a capacitive touch controller (which is switched off) and the output from a voltage monitor IC which generates a pulse of 50mS.

What I meant about you being on the right tracks was from one of your replies to a previous topic that was related to this.

@armor, I understood the “right track” part but I am trying to understand why sleep() is not working sometimes. The only reason I can think of is that the D4 pin conditions are either floating or “noisy” when you call sleep, causing a false and immediate wake from sleep. When you say the capacitive touch controller is “switched off”, perhaps its output goes HiZ, leaving the one input of the OR gate floating. On a CMOS gate, that is never good and makes it susceptible to stray charges. Food for thought.

This was an idea that was explored and discounted as there is a software debounce in the code just before the System.sleep(); The button1 pin / D4 must be low for at least 100mS.

int c = 0;            //debounce the wake button in case this is the cause of the occasional not sleeping issue
while (c < 100)
{
    if (pinReadFast(button1) == LOW) c++;
    else c = 0;
    delay(1);
}

I think there is something else in the code that is driving this - I just need to add it back bit by bit until it goes unreliable again! Oh joy.

[Edit] I just tried pinMode(D0, INPUT); and pinMode(D1, INPUT); this worked once, so maybe the sensor was pulling power through the signal line to the GPIO expander and the I2C bus. Not clear why it is not working after first time.

@armor, I’m confused. You are using D4 to wake from sleep but you debounce it BEFORE sleepint. What do you think happens when you release the button? I am assuming the debounce code doesn’t block, indicating that D4 has been low for 100ms. Perhaps you need sample D4 before and immediately after your sleep() to see if it has changed states and caused the wake. I’m not sure what else in the code could be affecting your sleep() WHILE you are sleeping unless it is something preventing your sleep() code from executing in the first place.

I am reading button 1 immediately after sleep to determine whether a button 1 HIGH or timeout condition occurred. It is not coming out of sleep because of noise on the button 1 pin.