nerdralph / picoCore

size-optimized Arduino/Wiring core for tiny AVR MCUs
MIT License
28 stars 4 forks source link

Pin must be constant for digitalWrite() #4

Closed Kaspi314 closed 3 years ago

Kaspi314 commented 3 years ago

I am trying to switch a multiplexer but it is giving me this error no matter how I try to do it without actually unrolling the whole function.

I want to dynamically switch pins based on bits in a for loop (or even possibly all at once using a single byte.) but the error says that it "must be constant" what is that?

#define S0 0
#define S1 1
#define S2 2
#define S3 3
#define SIG0 4
#define ASIG0 A2

uint8_t switch_pins[] = {S0, S1, S2, S3};

uint8_t current_channel = 0;

uint8_t switch_channel(uint8_t channel = 0)
{
  channel &= 0x0F;
  uint8_t pin;

  for (uint8_t i = 3, mask = 1; i < 8; i++, mask = mask << 1)
  {
    pin = i - 3;
    if (channel & mask)
    {
      // bit is on
      digitalWrite(switch_pins[pin], HIGH);
    }
    else
    {
      // bit is off
      digitalWrite(i - 3, LOW);
    }
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  switch_channel(0);
}

void loop() {
  // put your main code here, to run repeatedly:

}

void motorA_cw(uint8_t duration) {
  pinMode(SIG0, OUTPUT);
  switch_channel(14);
  digitalWrite(SIG0, HIGH);
  delay(duration);
  digitalWrite(SIG0, LOW);
}

void motorA_ccw(uint8_t duration) {
  switch_channel(15);
}
Kaspi314 commented 3 years ago

The error seems to be coming from this code in Arduino.h:

    if (!__builtin_constant_p(pin)) badArg("pin must be a constant")

__attribute((always_inline))
inline void check_valid_digital_pin(uint8_t pin)
{
    if (__builtin_constant_p(pin)) {
        if (pin >= NUM_DIGITAL_PINS) badArg("pin out of range");
    } else {
        badArg("pin must be a constant");
    }
}

additionally I have tried using constant integers but am still getting this error:

#define S0 ((int)0)
#define S1 ((int)1)
#define S2 ((int)2)
#define S3 ((int)3)
#define SIG0 ((int)4)
#define ASIG0 A2

uint8_t switch_pins[] = {S0, S1, S2, S3};

uint8_t current_channel = 0;

void switch_pin(uint8_t pin, bool value) {
  switch(pin)
  {
    case S0: 
    {
      digitalWrite(S0, value);
      break;
    }
    case S1: 
    {
      digitalWrite(S1, value);
      break;
    }
    case S2: 
    {
      digitalWrite(S2, value);
      break;
    }
    case S3: 
    {
      digitalWrite(S3, value);
      break;
    }
  }
}
Kaspi314 commented 3 years ago

This is fixed by not using defined constants in an array. I'm not sure why the compiler can't do this.

#include <stdlib.h>

// Signal switch registers ATTiny85 - CD74HC4067
#define SIG0 4
#define ASIG0 A2

uint8_t current_channel = 0;

uint8_t switch_channel(uint8_t channel = 0)
{
  channel &= 0x0F;
  uint8_t pin = 0;

  for (uint8_t i = 3, mask = 1; i < 8; i++, mask = mask << 1)
  {
SWPIN:
    pin = i - 3;
    if (channel & mask)
    {
      switch (pin)
      {
        case 0:
          {
            digitalWrite(0, HIGH);
            goto SWPIN;
          }
        case 1:
          {
            digitalWrite(1, HIGH);
            goto SWPIN;
          }
        case 2:
          {
            digitalWrite(2, HIGH);
            goto SWPIN;
          }
        case 3:
          {
            digitalWrite(3, HIGH);
            goto SWPIN;
          }
      }
    }
    else
    {
      switch (pin)
      {
        case 0:
          {
            digitalWrite(0, LOW);
            goto SWPIN;
          }
        case 1:
          {
            digitalWrite(1, LOW);
            goto SWPIN;
          }
        case 2:
          {
            digitalWrite(2, LOW);
            goto SWPIN;
          }
        case 3:
          {
            digitalWrite(3, LOW);
            goto SWPIN;
          }
      }
    }
  }
  current_channel = channel;
  return channel;
}

void setup() {
  // put your setup code here, to run once:
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  switch_channel(0);
}

void loop() {
  // put your main code here, to run repeatedly:

}

void motorA_cw(uint8_t duration) {
  pinMode(SIG0, OUTPUT);
  switch_channel(14);
  //digitalWrite(SIG0, HIGH);
  delay(duration);
  //digitalWrite(SIG0, LOW);
}