Analog PIN numbers

Porting some code to Giga, discovered a subtle issue with the Arduino PIN numbers on the analog inputs. The previous code that I inherited from a Uno used PIN numbers instead of name for the analog inputs, like 14 for A0, 15 for A1, etc.

This does not work on the Giga. Those PIN numbers identify additional serial port pins on the Giga, and if you try to perform an analogRead() on those pins, it crashes the board. Changing to the more standard A0, A1, etc., fixes the problem.

By the way, don't be confused by the Giga cheat sheet page, which claims there is an extra argument value to analogRead() only(?) for the Giga:

value = analogRead(pin, value);

This seems to be a typo. Also, you might be better off if you force the ADC resolution. Confusingly, the documents state that the default resolution on the Giga is 10 bits, but if you examine the preprocessor variable ADC_RESOLUTION you see 12 bits. I didn't take the time to test which is true, and just forced it to 16 bits thus removing the ambiguity.

// default ADC_RESOLUTION, 12 bits, is predefined by Arduino 
// but Giga has ADCs that are 16-bit capable, needs to be set
#undef ADC_RESOLUTION
#define ADC_RESOLUTION (16)
static constexpr uint32_t ADC_MAX_COUNTS = (1 << ADC_RESOLUTION) - 1;
// configure the ADC for full 16-bit operation
analogReadResolution(ADC_RESOLUTION);
Serial.println(
    "ADC nbits="+String(ADC_RESOLUTION) +
    ", max counts="+String(ADC_MAX_COUNTS) );

What values do you get if you print A0, A1, A2 etc ?

2 Likes

Good question...

Serial.println("A0 " + String(int(A0)) );
Serial.println("A1 " + String(int(A1)) );
Serial.println("A2 " + String(int(A2)) );

yields

A0 76
A1 77
A2 78

Presumably you can use those pin numbers safely with analogRead()

By the way, you should not need to convert the #defined analogue pin names to int as they are already ints. If the Giga supports printf(), as I expect it does, then you avoid the cast to String as well

Serial.printf("A0 %d\n", A0);
1 Like

Good to know. I am not experience in things Arduino, and really cursed the Serial.print() method when I was working on the older Uno code. Moving everything over to more standard printf() has been on my to-do list. It's good to know that Serial how has it's own printf() function built-in.

I have not checked that Serial.printf() is supported on the Giga but would be surprised if it were not

As an alternative you could use sprintf()

char buffer[20];
sprintf(buffer, "A0 %d\n", A0);
Serial.print(buffer);

AFAIK - I don't believe the Serial.printf() or Serial1.printf...

Is implemented as part of the GIGA Arduino code base. Although printf code is probably in every
sketch.

There is a few different ways to use printf...

One way is if you put the line:
REDIRECT_STDOUT_TO(Serial)

toward the top of the sketch then everything that goest out to STDOUT goes to Serial
including. printf.

Also some have used a library: #include <LibPrintf.h>

As for compatibility: I know with some boards, like the Teensy boards, and I believe here:
If you pass in a pin number < I believe 14, it will do the same as if you passed in:
14 which was A0. If you pass in a pin number >= A1 definition, that is the actual pin number it will use.

That is for example on a Teensy 4.1


Sorry I know slight diversion:
If you pass in 0 or 14, or A0 they will all read the same pin...

Issue here is on the GIGA they defined:
#define PIN_A0 (76u)

Their analogRead code does:

int analogRead(pin_size_t pin)
{
  if (pin >= PINS_COUNT) {
    return -1;
  }
  PinName name = analogPinToPinName(pin);
  if (name == NC) {
    return -1;
  }
  mbed::AnalogIn* adc = analogPinToAdcObj(pin);
  if (adc == NULL) {
    adc = new mbed::AnalogIn(name);
    analogPinToAdcObj(pin) = adc;
#ifdef ANALOG_CONFIG
    if (isAdcConfigChanged) {
      adc->configure(adcCurrentConfig);
    }
#endif
  }
  return (adc->read_u16() >> (16 - read_resolution));
}

And the tricky thing is: analogPinToPinName

#define analogPinToPinName(P)       (P >= PINS_COUNT ? NC : P < A0 ? g_APinDescription[P+A0].name : g_APinDescription[P].name)

And so now 14 < A0 (76) so it is trying to look up the name for pin 90

And in their variant.cpp file D90 is in SPI1
{ PD_7, NULL, NULL, NULL }, // D90 MOSI

And my guess is that in their code I showed above:
adc = new mbed::AnalogIn(name);
probably returns null or the like as it is not a valid analog pin. or something similar.

i.e. no error checking.
If you pass in pin number 40 as maybe I took a sketch from the Teensy I built it and forgot to convert which pin...
It would try to read their g_APinDescription[76+40] table
and index 116 exceeds the table, which only goes up to 102...

Sorry maybe too much info...

1 Like

Probably not helping but using 14 for A0, 15 for A1 etc "breaks" the hardware abstraction layer; these numbers only apply to 328P based boards. You did experience that yourself with the Giga but it also applies to the Mega, the Leonardo etc.

In my opinion you should always use the Ax numbers for pins; it does not matter if you use analogread() or digitalRead()/digitalWrite().

2 Likes

Good point. This is a program I inherited and was trying to make as little ripple as possible in the beginning. Now that I’ve moved to a Giga, that’s a long forgotten goal.

I was actually going to get away from the Arduino entirely, but the need for additional speed and more peripherals (mostly counter timers) happened quicker than I expected. I discovered by accident the Giga board, I have some familiarity with the H7 already, and leaving the project in the Arduino ecosystem has some benefits for my client. I decided to take the leap. A few struggles here and there but nothing terrible. I am a little worried about how slowly the Giga is being adopted by others and therefore the community isn’t as active as the more established boards.

Personally, I almost never have used the A0, numbers, why? They are not that much of an abstraction. And in most cases that is just one usage of a pin. Likewise on many of these boards there are additional pins that you can do analogRead on, for example the UNO Minima:

There are other pins on the right hand side that are marked as Analog, but there is no Ax number shown... And I am typically coding for some specific board...

But my things are, I don't personally like:

#define analogPinToPinName(P)       (P >= PINS_COUNT ? NC : P < A0 ? g_APinDescription[P+A0].name : g_APinDescription[P].name)
  1. Where it adds A0 to any pin number < A0. I would personally have restricted it to < 14 to handle any really old sketches for the really old boards (UNO R0).

  2. Passing in a wrong pin number causes the board to fault and probably go into the blink mode...

Note: i have mostly played with the Giga (earlier the UNO R4s) as a distraction from my other
distractions. I mostly play with Teensy boards by PJRC. With the GIGA I was/am curious about the dual cores and also to play with the display and the like.

Slow adaptation: My guesses why.
Cost: board plus display ~$135

Perceived reliability: several reports about display not working, parts overheating, touch not working...

State of Software: For some of the these newer boards including GIGA, and UNO R4. It feels like the stuff is in Alpha or Beta test state. I have tried out the new board release to see what things have improved.

Slow Builds: It feels like, when I build for these boards it takes a lot longer than it does for most any other board. Like several times longer. Probably has to do with MBED.

Don't get me wrong, there are a lot of interesting things with these boards as well!

But now back to my current primary distraction, and trying to receive JPEG images from some different camera modules (OV2640 and OV5640) on a Teensy 4.1 or MicroMod and display them on some different TFT displays such as an ILI9488...

Good luck

1 Like

I'm fine with the fact that you want to rewrite your sketches when you have to switch from Uno to Mega :smiley:

1 Like

:laughing:

Not a problem for two reasons:

  1. I have not used either an avr based UNO nor a MEGA for probably more than a decade.

  2. I usually try to have some form of define that describe what the pins are used for. instead of either 14 or A0. That is I would much rather see something like:
    analogRead(VOLUME_METER_PIN) versus with using A0 or 14...

  3. (oops cannot count :smiley: ) - I really do not like all of those generic #defines that keep getting added.
    I have run into issues where for example someone has a structure like:

typedef struct {
    uint32_t A0;
    uint32_t D0;
    uint32_t A1;
    uint32_t D1;
} my_struct_t;

my_struct_t myst;

And end up with some really cryptic error messages.
Wish they were done some other way, enum? name space? ...

4)...

const int FirstButton = 3;
const int LastButton = 9;
etc. is a much better way to do pin stuff, I find. YMMV, but I agree #define can be a hot mess.

const keeps you from inadvertently doing oopsies like
if(FirstButton = 9)

Don't worry about storage, const ints like that just get folded into the code.

About the only magic number in my code tends to be the baud rate for Serial. Used once, forget it.

At the risk of taking this thread even more off-course...

I was seriously thinking of a Teensy as the growth path for this project, not that I have any experience with the Teensy other than I have on kicking around in my toolbox. But when I found the Giga, like you, several of the features caught my attention. The dual core was interesting, and the reported ability to have Micropython running on one core and your C++ application on the other was intriguing -- there have been many times when I wanted to pop into a Micropython shell and manipulate the hardware for experimenting (I haven't done this yet, but I will certainly explore that later on).

This project needs a display. While I was thinking of a small 1-inch OLED I2C or SPI module, the ready-to-go monster (relatively speaking) display was attractive, with touch-screen as well.

My project needs to drive stepper / solenoid coils as well, and the existing hardware was in flux (pun intended). Having an official motor driver shield was certainly attractive as well. It uses one of the chips I was testing with, and was a great fit for this prototype I'm working on.

Slow adaptation: My guesses why.
Cost: board plus display ~$135

That is true for a hobbyist. In my present circumstances, I felt that the price was warranted because it let me focus my efforts on the client's project. The theory is that the Arduino ecosystem already exists and would take less time than rolling my own solutions from scratch on a different platform. This notion hasn't been perfect, but it is still valuable. I can defer design of a final production MCU board until other more critical aspects of the project have been worked out.

Bonus -- I told my client that if this board failed to do the job, I was happy to take it myself as a platform to experiment with on my own.

Slow Builds: It feels like, when I build for these boards it takes a lot longer than it does for most any other board. Like several times longer. Probably has to do with MBED.

Yeah, I read about and experienced this, too. Especially with the driver library for the display linked in, it takes forever. I vaguely recall setting up an Arduino Uno build a few years ago to recompile less often -- it seemed to be building all files whenever you compile, vs only compiling those files which have changed, like happens in other build systems.

1 Like

To keep from having your thread go too far off-course...
There is another thread:

As well as one on the Teensy forum that talks about the differences with pluses and minuses...

Sorry if I am a little distracted. I keep playing with several different things:

My current desktop is sort of loaded up with stuff :smiley:


I still have on it the GIGA with the display toward the top. Also with the Portenta H8.
And then Several Teensy boards, The one I am playing with right now is the one at the bottom.
Which is a Teensy Micromod in the Sparkfun ATP board and a quick and dirty shield I did, that brings out all of the pins WIth Teensy pin numbers, plus Camera connector and connectors for a couple
of different types of displays. The one on it right now is an ILI9488 (480x320) $17 at Amazon... It also has touch. Some of the others shown are the ILI93441 320x240 also with touch. Currently testing with Adafruit 5840 camera 5MP using FlexIO.... The one to the left is Teensy T4.1 with my own board, currently with ILI9341, testing the cameras using their CSI subsystem...

And there are several of the different camera modules that I have to plug into to these and some of them in the GIGA. They currently don't have support for some of the higher resolution ones.

Sorry for off topic....

Now back to the current diversions :smiley: Like yard work.

1 Like