9

Consider the following minimal example, where I set pinMode before calling SPI functions:

#include <SPI.h>

void setup() {
  pinMode(10, OUTPUT);
  SPI.begin(10);
  SPI.setDataMode(10,SPI_MODE1);
}

void loop() {
  delay(1000);
  SPI.transfer(10,1);
}

Now when SPI.transfer(10,1) is called in loop(), I always see that the slave selected pin goes down to 1.65V, but not 0 as it should! (see image below)

pin mode set before calling SPI functions

If we don't call pinMode(), like this:

#include <SPI.h>

void setup() {
  SPI.begin(10);
  SPI.setDataMode(10,SPI_MODE1);
}

void loop() {
  delay(1000);
  SPI.transfer(10,1);
}

We get what we would expect when calling SPI.transfer:

pin Mode not set

Is that a bug or do you have an explanation for that behaviour?

Thank you very much in advance for your time and interest!

3
  • Shouldn't it be SPI.setDataMode(10, SPI_MODE1);? Also only the second one is useful, as begin() calls setDataMode. Looking at the source code it looks like the SPI library doesn't alter the pin you specified (though I don't know ARM).
    – Gerben
    Commented Nov 6, 2014 at 17:06
  • Ja you are right, by accident I am calling setDataMode() twice. Tomorrow I will test the effect of SPI.setDataMode(10, SPI_MODE1); But why calling pinMode() has this effect is still not clear or? @Gerben
    – newandlost
    Commented Nov 6, 2014 at 21:34
  • @Gerben I modified my post
    – newandlost
    Commented Nov 7, 2014 at 9:23

1 Answer 1

1

It might have something to do with the internal pull up resistor. According to the SAM3X/A datasheet,

Control of the pull-up resistor is possible regardless of the configuration of the I/O line.

After reset, all of the pull-ups are enabled.

If you dig through all the include files you find:

../Arduino/hardware/arduino/samd/cores/arduino/wiring_digtal.c

Line 124 defines the pinMode(uint32_t ulPin, uint32_t ulMode) function. Examining the switch/case statement for INPUT vs INPUT_PULLUP vs OUTPUT you see the following:

  1. INPUT sets a register to reg = PORT_PINCFG_INEN.
  2. INPUT_PULLUP sets a register to reg = (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)
  3. OUTPUT sets a register to reg &= ~PORT_PINCFG_INEN.

The 'register' in each case is the same. I cannot for the life of me find what value PORT_PINCFG_INEN or PORT_PINCFG_PULLEN are defined as, but they're no doubt just 8-bit masks (they're cast to uint8_t when they're assigned to the 'register'). Thus, we can assume that whichever bit controls input/output is active when asserted, as is the pullup bit. For example:

 PORT_PINCFG_INEN   = b'00000001';
 PORT_PINCFG_PULLEN = b'00000010';
~PORT_PINCFG_INEN   = b'11111110';

If pull-ups are enabled after reset, we can say that on reset:

 reg = b'xxxxxx1x';

Point (3) above strongly implies that the instruction is:

 reg = b'xxxxxx1x' & 'b11111110';
   so
 reg = b'xxxxxx10'; // pull-up is enabled!

Therefore, if you call pinMode(X, OUTPUT) before anything else you will end up with the pullup resistor enabled. Setting the pin to an input will clear the pullup enable bit, after which you can set the pin to an output and the bit will remain clear.

However, the whole arguement falls down with the simple fact that if you don't call pinMode() at all, the problem doesn't occur...

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.