I'm building a battery operated device and must shutoff MOSI pin during sleep because it leaks current through the SD card if I don't (about 400 µA).

Problem is, it won't stay off. I've looked at SPI documentation and as far as I know I just need to call spi.end() then set pinmode to output and finally digitalWrite LOW. I observe with an oscilloscope that it does go low upon my asking it to but only for about 1 µs (actually it goes low twice within a 5 µs time period).

I've also tried manually setting the pin low using the PORT registers and the behavior is the same... see relevant code:


//pinMode(pin_MOSI, OUTPUT);
//digitalWrite(pin_MOSI, LOW);

//Both above (commented out) and below result in the same behavior -- pin does not stay LOW

DDRB |= B00100000;            //set pin 5 as output
PORTB &= B11011111;           //set output low for pin 5


...As you can see there is a delay to ensure that it isn't being set high by some other code.

Is there some sort of SPI interrupt that automatically sets the pin high again?

Hardware details:

MCU: ATMEGA1284P; Programmer: Atmel-ICE

UPDATE (13-Mar-2019):

I didn't realize that SPI is implemented by Atmel in hardware directly (see datasheet page 105):

MOSI/PCINT13 – Port B, Bit 5 – MOSI: SPI Master Data output, Slave Data input for SPI channel. When the SPI0 is enabled as a slave, this pin is configured as an input regardless of the setting of DDB5. When the SPI is enabled as a master, the data direction of this pin is controlled by DDB5. When the pin is forced to be an input, the pull-up can still be controlled by the PORTB5 bit.

I am currently chasing down this latest information and will hopefully come to a resolution soon. I will post any progress.

  • is it a SD module with logic level conversion?
    – Juraj
    Mar 13, 2019 at 5:01
  • @Juraj: No level shifting, straight 3.3 volts to the SD card.
    – DatuPuti
    Mar 13, 2019 at 15:51
  • I thought you using SPI.begin() and SPI.end() to use the embedded hardware from the Arduino IDE. You are bit-banging instead?
    – CrossRoads
    Mar 13, 2019 at 17:00
  • @CrossRoads: I'm using SPIClass from <spi.h>. I'm assuming that is part of the Arduino core but I'm not certain. I have successfully gotten it to work by clearing the SPI enable bit (SPE) from the SPCR register so I know the library was not doing it for me.
    – DatuPuti
    Mar 13, 2019 at 17:05
  • @Juraj: I'm using ATmega1284P which is a 3.3 volt MCU -- doesn't have 5 volts. Thanks!
    – DatuPuti
    Mar 13, 2019 at 17:46

1 Answer 1


Indeed, SPI is hardware implemented. I was able to get the MOSI pin to operate as intended by clearing the SPI enable bit from the SPCR register as follows:

SPCR &= 0B10111111;  //disable SPI

To re-enable after sleep, I'm assuming I'll just do SPCR |= 0B01000000; ...pretty sure that will work but I'll update here if I have to modify my solution.


Perhaps also pertinant information:

I was using an object of SPIClass in SPI.h which is from the Arduino core libraries -- for some reason it wasn't disabling SPI in hardware when calling the spi.end() method, maybe because there was some other SPI object initialized by some other library. Here is the source from SPI.cpp for the end method:

void SPIClass::end() {
  uint8_t sreg = SREG;
  noInterrupts(); // Protect from a scheduler and prevent transactionBegin
  // Decrease the reference counter
  if (initialized)
  // If there are no more references disable SPI
  if (!initialized) {
    SPCR &= ~_BV(SPE);
    interruptMode = 0;
    inTransactionFlag = 0;
  SREG = sreg;

The line SPCR &= ~_BV(SPE); should have done the job for me but I'm guessing it never got there because initialized was probably still non-zero.

  • If you didn't have #include <SPI.h> at the top of your sketch, how were you able to use SPI.begin(), SPI.transfer(); etc?
    – CrossRoads
    Mar 13, 2019 at 17:39
  • @CrossRoads: I did have SPI.h included -- sorry if that was not clear.
    – DatuPuti
    Mar 13, 2019 at 17:45
  • I thought I read something about not using the library, but I don't see it now. Perhaps I had two topics confused. Glad you got it sorted.
    – CrossRoads
    Mar 13, 2019 at 18:35
  • Perhaps the SPI library got improved in the years that passed since this answer was written. spi.end() has the desired effect now. Setting/clearing the bit in SPCR is still faster though. Oct 29, 2019 at 14:55
  • 1
    @DmitryGrigoryev: Take a look at the end() method that I copied from the core source files (above toward the end of my answer). If the member variable 'initialized' (which is defined as uint8_t) is not zero then clearing the SPI enable bit in SPCR never happens. I think the issue is that one of the libraries I was using called SPI.begin() but never called SPI.end() which means SPI was never able to deactivate. I ended up rewriting the code without the other libraries and the problem was solved.
    – DatuPuti
    Oct 29, 2019 at 21:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.