[Education] Demystifying Microcontrollers: Using ATmega328P and Assembly to Understand Registers

You have always presented your ASM approach as being intended to help users who were struggling to understand what was going on when they used C/C++

However, if I remember correctly, your posts extolling its virtues were not made in response to such problems. It seemed to me that you were suggesting it as an alternative to almost every problem presented and that was not appropriate, hence the warning from the moderators, including me.

An example :
See your post in

However, if someone posts something like

I need help understanding how digitalWrite() turns on an LED

then it would be appropriate to suggest using your ASM toy as part of the explanation

That is why I asked

But I have been a good guy! If you look back, I only intervened with my ASM approach in 1 or 2 posts, not more than that.

Regarding the deletions, I actually accept that the moderators delete my posts without giving explanations if they consider them inappropriate. I won't ask why anymore, because I already know the reason: the moderator simply considered it out of place.

I completely understand your point now about when it is appropriate (like explaining how digitalWrite() works behind the scenes) and I agree with that approach. My only real fear now is getting banned from the forum!

ma come sono stato un ragazzo bravo , e se vedi solo 1 o 2 post ho intervenuto con mio asm , non di piu , ce problemma che se publico qualcosa , il moderatore cancella mio intervento , senza darmi spiegazioni , perche capisco motivo?

You have to do something pretty extreme to get banned from the forum such as being a serial offender and taking no notice of warnings for which you might get a short suspension

Thank you, that is a big relief to hear! I'm glad to know that I don't have to worry about a permanent ban as long as we keep communicating like this.

Since I noticed that the people active in this thread make up almost 100% of those who regularly reply to user questions on the forum, and since you browse the forum every single day, could you link or write directly here what kind of thread would be the most appropriate to reply to using ASM? This would be at least for the beginning, just to see if it works and to avoid being too invasive.

If I see such a topic I will let you know by replying to it and notifying you by using @costycnc in the reply

However, I feel that I should warn you that I don't remember ever seeing such a topic

I feel that you would be better off promoting your assembler as an introduction to ASM for those who already know some C/C++ and want to explore the possibilities of using ASM

Of course, your assembler is quite limited and you can't go very far with it, but it is a starting point.

Exactly, that is what I have always tried to do!

However, presenting my tool here to users who already have the Arduino IDE installed and know how to use it doesn't make much sense. My tool is meant more for absolute beginners who have never touched programming before.

For those who already know some C++ and want to dive deeper into ASM, it is much better to use the official Arduino IDE along with extern "C". Even though finding the compiled assembly code can be difficult when you disassemble the binary, we can easily identify it by placing a block of 10 NOP instructions at the beginning and at the end of the ASM block. Alternatively, my tool could just be used as a disassembler for that purpose.

Exactly ,this i try to did ever! but also can use extern c if my tool is too primitive! also present my tool here where utents have already installed arduino ide and make some example, non ha sense , mio tool e di piu per uelli che non hanno tocato mai programare ,per quelli che vogliono aprofondire un po di asm puo usare arduino ide con extern c , pero sara difficile quando disassemble il codice , pero con un blocco di 10 nop a inizio e fine sara facile identificarlo o forse mio tool usato solo per disasemblare.

Thank you!

Then I would suggest that the Arduino forum is not the ideal place to promote it as it is highly unlikely that a new user will join the forum without having installed the IDE.

How many first posts have you seen that say something like

How do learn to program my Arduino ?

These days they are much more likely to ask AI

I asked Claude "how should a new arduino owner learn to program it ?"

The reply started with

1. Start with the Arduino IDE and built-in examples
Install the Arduino IDE, plug in the board, and work through File → Examples → 01.Basics in order: Blink, then AnalogReadSerial, DigitalReadSerial, Fade, etc. These are tiny, self-contained, and each teaches one concept (digital I/O, analog input, PWM, serial communication).

2. Learn C++ basics alongside the examples
Arduino code is C++ under a friendly wrapper. You don't need deep C++ knowledge to start, but understanding variables, functions, if/for/while, and arrays will unblock you fast. Free resources: the Arduino Language Reference on arduino.cc, or a short C tutorial (the syntax overlaps heavily).

and carried on in the same vein
Only at paragraph 6 did it suggest

6. Join a community for debugging help
r/arduino and the Arduino forums are active and beginner-friendly.

It went on to say

One thing worth knowing going in: the Arduino "language" is really C++ plus a hardware abstraction layer (digitalWrite, analogRead, etc.) sitting on top of AVR-libc, which itself sits on top of the same registers you'd touch in raw AVR assembly. So Arduino is a great on-ramp precisely because it hides register-level details like DDRB/PORTB until you're ready to peek under the hood — which, if they ever get curious about what's really happening, is a natural next step down.

The “Just Do It” Paradox

An absolute beginner can be told:

“Write digitalWrite(13, HIGH). You don't need to know what is inside it yet. It turns on the LED.”

But the beginner is still expected to write the surrounding C++ structure:

void setup() {
    digitalWrite(13, HIGH);
}

void loop() {
}

So, before the beginner even reaches the instruction that turns on the LED, they have already encountered:

void, setup(), loop(), parentheses, braces, semicolons, capitalization, and the distinction between functions and blocks.

All of that is simply accepted as part of learning Arduino.

Now consider giving the same absolute beginner this complete Assembly program:

.org 0
jmp init

.org 0x60
init:
    sbi 5, 5

loop:
    rjmp loop

and saying:

“Copy it, click Upload, and watch the LED. You don't need to understand everything yet.”

Why is that suddenly considered bad pedagogy because it is Assembly?

The beginner can initially treat .org, jmp, sbi, and rjmp exactly as they treat digitalWrite(): as things they are using before they fully understand them.

And visually, the Assembly version is arguably more direct. Every line is an instruction or a very simple directive/label. There is no additional C++ scaffolding around the operation.

That is the paradox:

C++ is allowed to say “you don't need to know what digitalWrite() does yet,” while still requiring the beginner to learn the syntax surrounding it.

But when Assembly is presented with a few instructions that the beginner can simply copy and run, suddenly people say:

“No, you must understand Assembly first.”

Why?

The beginner can start with:

Copy → Upload → LED ON.

Then, once the LED works, we open the box:

.orgjmpsbirjmp → registers → bits → hardware.

The point is not that Assembly is magically easier than C++.

The point is that the beginner does not need to understand everything before being allowed to make something work.

And that rule should apply equally to both.

The beginner is not expected to write the sketch structure as it will be done when they do File/New or, of course, they could be given the whole sketch to copy/paste into the IDE

Using your logic, before the beginner uses your compiler they are will have encountered .org and a number, jmp and some text, .org again but with a strange incantation after it this time, a word followed by a colon, a meaningless 3 letter combination followed by two numbers that have no context, then another word followed by a colon and some gobbledegook to do with it.

As you say,

That goes for both ways of programming, but the crucial difference is that digitalWrite(13, HIGH); has some English words in it and a number that relates to a pin label on the board

You say that 13 is intuitive because it relates to a pin label on the board, but let's be honest: PB5 was simply 'baptized' as D13 by Arduino due to the sequential mapping of the hardware ports!

The designers mapped the digital pins in a very logical sequence:

  • PORTD mapping: From PD2 to PD7 (since PD0 and PD1 were busy with RX/TX).
  • PORTB jump: Right after, from PB0 (D8) straight up to PB5, which became D13.

Don't get me wrong, Arduino is a wonderful gift to humanity—it completely democratized electronics! But in a way, it also 'ruined' Assembly by changing the pin names :grinning_face: :grinning_face: :grinning_face:

I say this from experience. When I started, I was so confused when I saw people in old forums talking about PB5 for what I knew as D13.

You make my point for me.
PB5 has no obvious connection to D13

:magnifying_glass_tilted_left: Where is PORTA on the ATmega328P? (The Missing Silicon)

Internally, PORTA does not exist at all. There is no physical silicon and no software register for it inside the chip.

If you try to write PORTA in your C++ or Assembly code, the compiler will immediately throw an error. That memory address simply does not exist in the register mapping of the ATmega328P.

:world_map: The Internal I/O Memory Map

The internal input/output (I/O) memory structure skips the letter 'A' completely. The peripheral blocks are tightly packed in sequence:

  • :package: PORTD Block: Addresses for PIND, DDRD, and PORTD registers.
  • :package: PORTC Block: Addresses for PINC, DDRC, and PORTC registers.
  • :package: PORTB Block: Addresses for PINB, DDRB, and PORTB registers.

There are no "holes", blank spaces, or hidden ghost registers called PORTA between them. The logic circuitry that would have managed a PORTA was entirely omitted before the chip went into production.

:factory: Why Do Chip Manufacturers Do This?

Microcontroller designers work with modular chip families. Instead of designing every single chip from scratch, they pick ready-made peripheral blocks from an internal catalog:

  • :chart_decreasing: Low-pin count chips (like ATmega328P): They only get blocks B, C, and D to save physical space.
  • :chart_increasing: High-pin count chips (like ATmega2560 on Arduino Mega): They get block A, E, F, and many more.

:light_bulb: Fun Fact: Why did Atmel kill PORTA instead of PORTD?

You might wonder: if Atmel had to shrink the chip down to 28 pins, why did they sacrifice PORTA instead of PORTD? It wasn't a random choice; it was pure hardware strategy!

Microcontroller ports aren't just for turning pins ON and OFF; they also house special hardware functions. Atmel couldn't touch PORTD because it contains the absolute "heart" of the chip's communications:

  • :electric_plug: The Serial Interface (PD0 & PD1): Without PORTD, we wouldn't have hardware RX and TX. No serial communication means no uploading code from the computer!
  • :high_voltage: Hardware Interrupts (PD2 & PD3): These pins host INT0 and INT1, the only hardware pins capable of waking up the microcontoller instantly from a deep sleep mode.

On larger chips, PORTA is used to house the ADC (Analog-to-Digital Converter). When designing the compact ATmega328P, engineers simply moved those analog channels over to PORTC (our A0 to A5 pins). Since PORTC took over the analog duties, PORTA was left with no special job—making it the perfect candidate to be completely erased from the silicon to save space.

Yet another reason why looking at the chip through Assembly makes everything so logical! :wink:

:gem_stone: The Beauty of Assembly

This is exactly what makes Assembly so fascinating. You are touching the true, raw physical architecture of the silicon. No software layer is hiding the missing PORTA from you. You see the chip exactly as it was built!


"Interesting, but I'm sure some of you already knew this!"

Interesting, pero sono sicuro che alcuni da voi lo sapeva gia!

offtopic: because this mcu has inscriptioned gravitech.us ?

Sure there are:


Right there in locations 0-2, marked "reserved."
You're right that there's nothing actually there, though.

If you try to write PORTA in your C++ or Assembly code, the compiler will immediately throw an error.

And if you're writing ASM in your style, you'll have something like sbi 2,5 and will assemble just fine, but won't do anything useful, nor give any indication that you did something wrong.

I'm not convinced. Why didn't they keep PORTA with the analog functions, and deleted PORTC? Moving analog to PORTC doesn't seem more difficult than moving I2C to PORTA...

Many times I have asked myself this question: do PORTB, PORTC, and PORTD really exist inside the ATmega328P? My answer is something like this: in reality, there are three groups of flip-flops/circuits or some other alternate functions. For the purposes of identification and addressing, these groups are simply named PORTB, PORTC, and PORTD. They could just as well have been named PRB/5, PRC/6, and PRD/7 without changing either the existence or the function of these flip-flops/circuits. The names are merely labels assigned by the designers; the underlying hardware remains exactly the same.

for this i like to use sbi 5,5 but for portability need to have a standard name that all knowing,is same how change name from car to cra

It is a philosophy: silicon can work even without the names humans give to it.

Thanks!

You know that first to published i want to put instead of "perhaps some know" to "its true?" ... and now i see that i wrong ,

Complaining about nonexistent PORTA is same as complaining about why the ASM instruction only accepts certain numbers.

so if put bbb 000,001,002 is executed but did nothink?

this is avrlass.js

Reserved bits should be written 0 - compatibility reasons. Probably nothing will happen if there is 1. PINC7 is reserved bit
Reserved I/O memory addresses should never be written. The first one is 0x00 (0x20). Try it if you're not afraid. I think, nothing will happen.

EDIT:
I tried it in Atmel Studio, nothing. Memory at 0x20 cannot be modified with STS, LDS returns 0.