Go Down

Topic: Mega 2560 pin names (Read 1 time) previous topic - next topic

Dr_Quark

Dec 12, 2017, 05:53 am Last Edit: Dec 12, 2017, 05:54 am by Dr_Quark
On the mega, along the left side, port K (PK0) is shown variously as pin 8, pin 89, PK0, A8, and ADC8. Along the bottom edge, pin 53 is also shown as A8. When you do a pinMode(A8, OUTPUT), the pin that is set is 89/8 on the left side. Addressing this pin as PK0, eg, pinMode(PK0, OUTPUT), does not create an error message, but it also doesn't set the pin.

Why is pin 53/PC0 along the bottom edge also labeled A8?

thanks. this only took an hour to figure out why I couldn't get pin 89/8 to function properly. I've been using Nanos and Pro-minis almost exclusively up till now, and they don't have any repeated/duplicate pin names.
Dr.Quark

pert

#1
Dec 12, 2017, 06:16 am Last Edit: Dec 12, 2017, 06:17 am by pert Reason: Link to pin mapping page
You need to understand the difference between the Atmel pin designation (in this case PC0), the physical pin number (in this case 53), the special function notation (in this case A8), and the Arduino pin number (in this case 37). For use in the Arduino core library functions such as pinMode(), digitalWrite(), digitalRead(), etc. the only one that matters is the Arduino pin number. The Arduino pin numbers are just arbitrary number assigned to conveniently identify the pin and they have no relation to any of the other designators you mentioned. You will never have success using any of those other designators with Arduino core library functions.

So in this case you can see the Arduino pin number mappings for the ATmega2560 in red here:


As for what the "A8" special function designator means. From consulting the "Port C Pins Alternate Functions" table on page 79 of the ATmega2560 datasheet we see:
Quote
A8 (External Memory interface address bit 8 )
It's unfortunate that in this case an Arduino pin number and Atmel's special function designator happen to have the same names but if you understand that they are talking about completely different things it's really not a problem.

krupski

On the mega, along the left side, port K (PK0) is shown variously as pin 8, pin 89, PK0, A8, and ADC8. Along the bottom edge, pin 53 is also shown as A8. When you do a pinMode(A8, OUTPUT), the pin that is set is 89/8 on the left side. Addressing this pin as PK0, eg, pinMode(PK0, OUTPUT), does not create an error message, but it also doesn't set the pin.

Why is pin 53/PC0 along the bottom edge also labeled A8?

thanks. this only took an hour to figure out why I couldn't get pin 89/8 to function properly. I've been using Nanos and Pro-minis almost exclusively up till now, and they don't have any repeated/duplicate pin names.
The various Arduino boards are setup to be easy to use. For example, "Pin 13" will always respond to programming such as "digitalWrite (13)" no matter what board you have. However, the exact PIN that is used for pin 13 (such as "PB7" or "PK0" will be different from board to board.

More advanced users like to access pins and ports directly (such as "PORTB |= _BV(7);" to turn bit 7 on Port B on, but that statement will only work on the particular Atmel chip (2560, 328p, etc...) being used.

Direct access bypasses the Arduino "translation" layers and gives you a bit more speed, but in most cases it's easier to say something like "digitalWrite (13, HIGH)" than it is to turn on a particular bit in a particular port to do the same thing.

Make sense?

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Dr_Quark

#3
Dec 12, 2017, 01:22 pm Last Edit: Dec 12, 2017, 01:24 pm by Dr_Quark
Well, blow me down. I thought I understood the Arduino pin mapping, but obviously not. For some reason I thought that these graphics that are common around the web would have some relation to the pin names used in the IDE:



So I'm looking at PK6, which is pin A14 and I see that TX3 is PJ1 and also pin 14. Now, for PJ1 is that just "14" or can it also be "D14" or "TX3" when used in a statement? Further, I see that PJ2 through PJ7 don't have an Arduino pin assignment, but I'm betting that they can be manipulated using direct port commands such as "PORTB |= _BV(7)" as in KRUPSKI'S example.

BTW, thanks for the pin assignment graphic.

But neither of your responses answer the question of why "A8" works in the compiler, but "PK0" does not, yet it doesn't create a compiler error. So "PK0" is obviously defined in the IDE--does that mean it is only appropriate in a certain class of statements, eg, direct port manipulation, but not in things like digitalWrite()?
Dr.Quark

Dr_Quark

While we're talking about port manipulation, I found the following in the Atmel reference library:

         _BV(3) => 1 << 3 => 0x08

I have no clue what this means. Why would you say _BV(3) when it is just as easy to say digitalRead(3)? On further reading, it looks like the above line implies that _BV(3) is equivalent to 0x08. If that is true, what does _BV(PD7) even mean?
Dr.Quark

UKHeliBob

Quote
So "PK0" is obviously defined in the IDE--does that mean it is only appropriate in a certain class of statements, eg, direct port manipulation, but not in things like digitalWrite()?
As a matter of interest have you tried printing it ?  What is its value ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Dr_Quark

I think I may resort to printing the value. As a quick check, I went into tools to change the board to "Nano" instead of "Mega 2560.") I also added the line:

   Serial.print(PK0) ;

The odd thing is that I thought that changing to a Nano, the compiler would recognize that PK0 wasn't an allowed variable, but it didn't. It was perfectly happy.

On the other hand, it allowed

   pinMode(A8, OUTPUT);

But produced an error here:

   digitalWrite(A8, HIGH);  ==> A8 not declared in this scope (correct for a Nano)

So why wasn't A9 flagged in the pinMode() statement, and why wasn't PK0 flagged in the Serial.print() statement?

Here's the values printed by Serial.print():

     PK0 = 0              ==> that doesn't make any sense to me
     A8   = 62

Dr.Quark

Dr_Quark

So I print:

     Serial.println(_BV(3)) ;

and it prints the numeral "8".

Seriously, the _BV() function is just a shift function? I fail to see how this adds clarity. Maybe for someone who is familiar with the oddities in the Arduino IDE, but an experienced programmer would recognize
1 << 3 or 0x08, but they wouldn't have a clue what _BV() was.

IMHO, this only helps to put a little more distance between the new programmer and the hardware.
Dr.Quark

pert

#8
Dec 13, 2017, 03:39 am Last Edit: Dec 13, 2017, 03:41 am by pert
For some reason I thought that these graphics that are common around the web would have some relation to the pin names used in the IDE
Of course they do. The numbers in pink are the Arduino pin numbers.

It's interesting how your extra knowledge is actually hindering you in being able to use the Arduino core API. A beginner will look at the numbers on the silkscreen on their board and just use them and it works fine without any confusion. They don't even really know what an ATmega2560 is or that its pins have different names in the datasheet and so long as they are using the Arduino functions they don't need to. Maybe it would be helpful for you to study the code that is used for the Arduino pin definitions. Here it is for the Mega 2560:
https://github.com/arduino/ArduinoCore-avr/blob/master/variants/mega/pins_arduino.h
Does that make things more clear?

is that just "14" or can it also be "D14"
Only 14. You will sometimes see it written as D14 to indicate "digital pin" 14 but you can't use that pin notation in the Arduino IDE.

I'm betting that they can be manipulated using direct port commands such as "PORTB |= _BV(7)" as in KRUPSKI'S example.
Sure, the Arduino pin functions are just intended to make the code more understandable to beginners and also make the code portable between different hardware. All the more efficient operations are still available to you. You can even use assembly if you want.

But neither of your responses answer the question of why "A8" works in the compiler, but "PK0" does not, yet it doesn't create a compiler error. So "PK0" is obviously defined in the IDE--does that mean it is only appropriate in a certain class of statements, eg, direct port manipulation, but not in things like digitalWrite()?
I also added the line:

   Serial.print(PK0) ;
If you look at line 1177 of {Arduino IDE installation folder}/hardware/tools/avr/avr/include/avr/iomxx0_1.h you see:
Code: [Select]
# define PK0 0
So there's no magic to PK0, it's just the bit number in the PORTK register for that pin. So of course the Arduino core library functions allow you to use PK0 as an argument since indeed there is a pin 0. It just didn't have your intended result. You just need to stop thinking you can plug anything other than Arduino pin numbers into functions that are written to take Arduino pin numbers.

The odd thing is that I thought that changing to a Nano, the compiler would recognize that PK0 wasn't an allowed variable, but it didn't. It was perfectly happy.
I can't reproduce that:
Code: [Select]
Arduino: 1.8.5 (Windows 7), Board: "Arduino Nano, ATmega328P"
C:\Users\per\AppData\Local\Temp\arduino_modified_sketch_807778\serial.ino: In function 'void setup()':
serial:4: error: 'PK0' was not declared in this scope
   Serial.println(PK0);
                  ^
exit status 1
'PK0' was not declared in this scope

PK0 should only be defined when you're compiling for ATmega640, ATmega1280, or ATmega2560.

krupski

While we're talking about port manipulation, I found the following in the Atmel reference library:

         _BV(3) => 1 << 3 => 0x08

I have no clue what this means. Why would you say _BV(3) when it is just as easy to say digitalRead(3)? On further reading, it looks like the above line implies that _BV(3) is equivalent to 0x08. If that is true, what does _BV(PD7) even mean?
The "_BV()" thing is just a macro that gives you the numeric value of a binary bit.

Look at this example: I want to blink the built in LED on an Arduino UNO, and I'll show you two different ways which LOOK different but are exactly the same.  First of all, I have to look something up: I know the LED is on Arduino UNO Pin #13, but I don't recall what port and bit that is (give me a sec)....  ... OK looking at the UNO schematic I see that Pin 13 is connected to the Atmel MEGA328p chip's pin 19 which is Bit 5 of PORTB.

OK, now the code. First the "Arduino way":

Code: [Select]

void setup (void)
{
    pinMode (13, OUTPUT); // set pin 13 to output
}

void loop (void)
{
    digitalWrite (13, HIGH); // turn LED on
    delay (500); // leave it on 1/2 second
    digitalWrite (13, LOW); // LED off
    delay (500); // leave off 1/2 second
}



Now, the "C way" using the ports and bits directly:

Code: [Select]

void setup (void)
{
    DDRB |= _BV(5); // set the data direction register for PORTB, BIT5 as an output
}

void loop (void)
{
    PORTB |= _BV(5); // set PORTB, bit 5 high (LED on)
    delay (500); // 1/2 sec, same as first example
    PORTB &= ~_BV(5); // PORTB, bit 5 low (LED off)
    delay (500); // same as the others
}



OK, what the heck is this |= and &= stuff?

Well, first of all, realize that we COULD have just said PORTB = _BV(5) or PORTB = 0 but that would "mess with" ALL EIGHT pins of PORTB.  In a more complex program that had, say, a few motors and a few LED's, messing with the whole port might start or stop motors when you only want the LED to blink.

Look at an 8 bit byte and the value of each bit:

Bit     7    6    5    4    3    2    1    0
Hex  0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01
Dec   128   64   32   16    8    4    2    1

so, Bit 5 (i.e "_BV(5)") is actually 32 (or 0x20 in hex) and assuming ONLY bit 5 were set, the byte would look like this:

Bit     7    6    5    4    3    2    1    0
        0    0    1    0    0    0    0    0

Or, in a program if I did this (pseudo code):
Print hexValue (_BV(5));
...it would print out "0x20" and.....
Print decValue (_BV(5));
... would print out "32".


Now, the "|" character, in C, means "logical OR" and "|=" means "OR-equals". OR is used to set bits HIGH. Think of it like this: I ask you "do you have coffee?" and you have two cups. If the first one OR the other one OR both are full, then yes you do have coffee.  Code example:

Code: [Select]

something = something | 0x20; // take value of "something" and set bit 5 high
something |= 0x20; // same exact thing, just simpler looking


OK, now we see that we use "OR" to turn a bit ON. To turn it off, we use AND. How AND works, in "coffee code":

I ask you "Are both of your cups filled with coffee?". If the first cup AND the second cup are full, then your answer is "YES", otherwise it's "NO".  So if I want you NOT to have both cups of coffee, all I need do is empty ONE or the OTHER or BOTH and then your answer is "NO".

Now, here's the trick of turning OFF bit 5 without disturbing the others. The "~" (tilde) character means "invert all the bits" (if a bit is 1, make it 0. If it's 0, make it 1.

So let's say now we are looking at PORTB and you had turned ON the LED (that is, set bit 5 high). It looks looks this:

Bit     7    6    5    4    3    2    1    0
PORTB   X    X    1    X    X    X    X    X


The "X" means "I don't care what those bits are".


Remember the AND function? If I "AND" any bit in PORTB with a high (1), then the result will be whatever the bit was originally (i.e it won't change).

To turn off Bit 5, I need to make an "AND MASK" like this:

Bit     7    6    5    4    3    2    1    0
_BV(5)  0    0    1    0    0    0    0    0

~_BV(5) 1    1    0    1    1    1    1    1 (this is the "AND mask" made using the tilde)


Now let's say PORTB has this state:

Bit     7    6    5    4    3    2    1    0
value   1    0    1    1    1    0    1    1

mask    1    1    0    1    1    1    1    1
result  1    0    0    1    1    0    1    1 (result after AND-ing in the mask)

Notice that "result" is the same as "value" except that we changed bit 5 (and ONLY bit 5) from 1 to 0 (which turns off the LED).

Hope all this makes sense. If not, read it again. It's actually simple (it only looks scary).

Hope it helps.

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Go Up