Strange behaviour setting pinMode by array

Hi All,

I've come across a strange behaviour when I set pinMode by an array.

The setup:

  • Arduino Nano
  • 10x LEDs wired individually (from ground, through resistors) to pins 2 to 11.
  • The wiper of a 10k pot wired to A7 (i.e. 0-5v input).
  • The code progressively lights up the LEDs as the pot is turned up.

The problem:

  • When I set pinModes individually, the code works fine.
  • When I set pinModes by a for loop and an array, the LED on pin 10 lights up, but is very dimly lit (all other LEDs light up as expected).

Here is the code that works:

int PINS[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

void setup() {
  // Manually set each output pin => works as expected
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(A7, INPUT);
}

void loop() {
  for (int i = 1; i <= 10; i++) {
    if (analogRead(A7) > i * 93) {
      digitalWrite(PINS[i - 1], HIGH);
    } else {
      digitalWrite(PINS[i - 1], LOW);
    }
  }
}

So I'm assuming that since that code works and all LEDs light up as expected, the hardware is operating and wired correctly.

Here is the code that has the dim LED on pin 10:

int PINS[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

void setup() {
  // Set each output pin using for loop => works EXCEPT FOR PIN 10 !!
  for (int i = 0; i <= 9; i++) {
    pinMode(PINS[i], OUTPUT);
  }
  pinMode(A7, INPUT);
}

void loop() {
  for (int i = 1; i <= 10; i++) {
    if (analogRead(A7) > i * 93) {
      digitalWrite(PINS[i - 1], HIGH);
    } else {
      digitalWrite(PINS[i - 1], LOW);
    }
  }
}

Doesn't matter where I put the "10" in the array, the LED on pin 10 is always dim.

Oh, and if I take that malfunctioning code, and just add pinMode(10, OUTPUT); after the pinMode for loop, it works correctly:

int PINS[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

void setup() {
  for (int i = 0; i <= 9; i++) {
    pinMode(PINS[i], OUTPUT);
  }
  pinMode(10, OUTPUT);  // Add this line and then the LED on pin 10 works correctly
  pinMode(A7, INPUT);
}

void loop() {
  for (int i = 1; i <= 10; i++) {
    if (analogRead(A7) > i * 93) {
      digitalWrite(PINS[i - 1], HIGH);
    } else {
      digitalWrite(PINS[i - 1], LOW);
    }
  }
}

Something weird going on with pin 10 and the pinMode for loop. Very strange. Any ideas ? Thanks !

i can't see anything wrong with the code and tested it myself

you might consider a simpler program to make sure things work as expected

#undef MyHW
#ifdef MyHW
byte PINS[] = { 10, 11, 12, 13 };
#else
byte PINS[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
#endif

#define N_PINS   sizeof(PINS)

void setup () {
    Serial.begin (9600);

    for (unsigned i = 0; i < N_PINS; i++)
        pinMode (PINS[i], OUTPUT);
}

void loop () {
    for (unsigned i = 0; i < N_PINS; i++) {
        digitalWrite (PINS [i], ! digitalRead (PINS [i]));
        delay (250);
    }
}

So as your setup function says:-

You are not initialising pin 10, the last value in your pins array.

Try

for (int i = 0; i < 10; i++) {
    pinMode(PINS[i], OUTPUT);
  }

It looks to me the same execution result.

Also, pin 10 is not the end of the array.

But the array index goes from 0 to 9, correct ?
So PINS[0] == 2
and PINS[9] == 11
The problem is with PINS[8] == 10

PINS [8] is 10

Correct :slight_smile:

And the last pin in the array (pin 11) works fine.

So you think I have a hardware problem maybe ?

don't know. go back to basics

Your program worked correctly. LED on pin 10 was the correct brightness.

try incorporating your changes

I'm sorry, I don't understand this part of your code. I'm just beginning. Could you please explain ?

i test code i post with my hardware but try to leave the existing HW parameters.

line beginning with # are compiler directives. #ifdef/#else/#endif effectively comment out code. when i tested, MyHW was defined ("#define MyHW) and the PINs after #ifdef MyHW took effect. MyHW is undefined and your PINS values will take effect

another common usage is

#if 0
 ...
#else
 ...
#endif

to effectively remove/comment out code when trying different things

Understood. Mostly. Thanks.

This is your problem. Remove this line.

DO NOT USE pinMode() ON PINS USED ONLY FOR analogRead().

Pins A6 and A7 are outside the range of digital pins so using pinMode() on them indexes off the end of two tables in the firmware. Pin A7 is accidentally mapped to Pin 10.

3 Likes

Good point. +1 :+1:

I feel this is worth fixing the core, but I don't know where to write this.
I shall call to @pert

Specifically, add two NOT_A_PIN to the end of the array below.
https://github.com/arduino/ArduinoCore-avr/blob/master/variants/standard/pins_arduino.h#L150

As long as A6 and A7 are defined, they should also be present in the array.
https://github.com/arduino/ArduinoCore-avr/blob/master/variants/standard/pins_arduino.h#L62
https://github.com/arduino/ArduinoCore-avr/blob/master/variants/standard/pins_arduino.h#L71

The pinMode function ignores from port-arrays whose data is NOT_A_PIN.
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_digital.c#L35

Oh wow, I can't believe I thought that was a thing. Thank you. I will try that and let you know how it goes.

Just tried it with that line removed. Worked perfect. That was it. Thank you !

It's a fairly natural mistake. You are using the pin as an 'input' so you set the pinMode() to INPUT. It works 100% of the time on an UNO and 99.99% of the time on a Nano. It's only that one case where you are setting A7 as an INPUT after setting Pin 10 as an OUTPUT that the problem manifests itself.

If I had not done a deep dive into the firmware the first (and only previous) time someone reported such A problem I never would have guessed that the firmware wouldn't check for out-of-range values.