How does Arduino actually turn on an LED? (The raw truth inside the chip)

This topic is to help me write a tutorial about how an Arduino turns an LED on and off, please post your suggestions and feedback here.


We all know that with Arduino, it is easy to turn on an LED with a simple line like:

digitalWrite(13, HIGH);

and the LED lights up.

But what really happens between this line of code and the LED producing light?

To make this concept easy to understand, imagine the microcontroller registers as a "cabinet full of switches". Each switch can be flipped UP (ON) or DOWN (OFF). Changing one of these switches changes the behavior of a microcontroller pin.

Of course, when you write digitalWrite(13, HIGH);, Arduino doesn't actually understand that language.The real process is more complex, but for learning purposes we can imagine that the final hardware action is equivalent to this raw instruction:

sbi 5, 5

What does sbi 5, 5 mean? Technicians call it Set Bit in I/O Register. But in our reality, it means: "Hey Arduino, flip UP switch number 5 inside cabinet number 5".

Because that is exactly what happens inside the chip: cabinet 5 is PORTB, which holds 8 switches. And switch number 5 is physically wired straight to pin D13 (the built-in LED on your board).

Now, let’s go to the webpage costycnc.it/avr1 and see if it is true.

Let's type sbi 5, 5, compile, and upload the code.

.org 0
rjmp start
.org 0x60
start:
sbi 5,5
loop:
rjmp loop

You will see that the LED turns on! It will light up faintly, but don't worry about the details right now.

Want to turn it off? Just write:

cbi 5, 5

Compile, upload, and Arduino listens to us blindly! Do you see? Arduino doesn't do magic; it just opens and closes switches.

I think this concept is extremely important: from now on, you will see Arduino in a completely different way. All those abstract names like PORTB, PORTD, or PORTC are just cabinets (numbered registers), and labels like PB5, PC1, or PD2 are just switches (BITS) that need to be opened or closed. And we could easily stop right here.

However, for those who love an adventure and want to dig deeper, a question might pop up: why is the LED light so faint?

Trust me, it is not easy to explain this with everyday words and without any previous technical knowledge on your part, but I will try. Forgive me in advance if the terms are not academic.

To set pin D13 as an output, we need to go to cabinet 4 (switch 5) and close it. This tells the chip that D13 is now a power output. Let's test it! Go back to the program, add sbi 4, 5 as well, and you will see that the LED now shines at full brightness.

For those who don't like an adventure, you can stop here. We get it: cabinet 4 handles pins D8 to D13 as either inputs or outputs. If I put a 1 (using sbi) in cabinet 4 at switch 0, pin D8 becomes an output. If I put a 0 (cbi), it becomes an input.

But for those who love an adventure and wonder why, let's move forward. You will see that it's worth it.

The difference between setting a pin as an output or an input is simply a resistor and a switch connected in parallel. When we do sbi 4, 5, we close the switch that bypasses the resistor. This way, the LED receives power directly from the 5V rail without going through that resistor. When we do cbi 4, 5, the switch opens and the 5V current is forced to pass through the resistor before reaching the LED (which is why the light was so faint!).

This is the famous internal pull-up, which most people do not understand. When we want to read the state of pin D13, we set it to pull-up: the current flows through the resistor and the pin will always stay at value 1 (HIGH). However, if we connect it to ground (0) from the outside, the value drops from 1 to 0. This keeps the pin from floating "in the air" and catching electrical noise, holding it securely to the positive side through that resistor.

I think stopping here is the right choice because for someone who knew nothing, this is already a lot to take in.

But I know some of you still love an adventure, so I will go just a tiny bit further just for you! :joy:

If you don't want to use the CostyCNC tool, you can try raw Assembly inside the classic Arduino IDE too. Just create a folder named ledon. Inside it, put two files: ledon.ino and ledon.S (it must be a capital S). When you press compile, Arduino automatically finds the .S file in the folder and includes it in the program. It's a bit more inconvenient, but totally possible.

CODE INO

// Tell Arduino that the function is external and written in C/Assembly
extern "C" {
  void led_on();
}

void setup() {
  // Call the Assembly function that will do all the work
  led_on();
}

void loop() {
  // Keep the loop empty: the chip has already done everything in the setup
}

CODE .S (ASM)

.global led_on

led_on:
    sbi 0x04, 5    ; Cabinet 4, switch 5 UP: Pin D13 becomes a power output
    sbi 0x05, 5    ; Cabinet 5, switch 5 UP: Light is ON at full brightness!
    ret            ; End of function: go back to the main program

One last thing and then I'll stop, promised! I left this for the very end so I wouldn't overload your brain.

Some might ask: why not make a tutorial about what happens inside newer boards like the Arduino Uno R4 or an ESP32? Why waste time with an old Arduino Nano using an ATmega328, which is considered slow today?

You are right, but you might not realize the internal complexity of a modern chip. The ATmega328 is perfect for learning: it has a simple architecture, immediate Assembly commands, incredible documentation, and an infinite amount of ready-made examples. Understanding the fundamentals of this MCU will allow you to understand the basics of any other microcontroller in the world. It was not a random choice at all.

And do you know what? Cabinet 5 and switch 5 actually exist, along with all the other cabinets and switches. You can see them for yourself if you want, written right inside the official datasheet from the manufacturer of the ATmega328. https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

page 280

And I apologize to those I managed to make read all the way to this point! Until the next tutorial... what do you say? Shall we talk about Interrupts?

Goodbye!

No, on and AVR microcontroller thay are in SERIES

not in this mode?

so the switch 4,5 is in paralel wirh resistor , but both in series with led!

anyway is pure educational , internal is more complicated, you remember i think in another tread how many schematics is published!

From the datasheet
The FET switch is in series with Rpu

yes, but is not complete from where give 5v ,when pin is set as output? in your schematic is only part here is set as input!

OK here is the complete diagram


Still in series

ok ... explain how is powered the led when is input (faint) and output (bright) , because your schematic not understand! i did in another thread that im not tecnician, programmer only a hobbyst!

@costycnc
"How does Arduino actually turn on an LED? (The raw truth inside the chip)"

I have connected the LED at DPin-13 with a series resistor to limit the current.

The circuit and Arduino UNO R3 are on the Table. I am sitted 2 yards far away on my chair.

I have wished to turn on the LED. How do I convert my this intention into action? Do you agree that the answer to this question will serve as an answer to your above question?

hello again! you are my friend!:grinning_face:

my message from bellow translated with ai:

I use pin 13 because it is the onboard LED and it already has a built-in resistor! You don't need an external LED or resistor. For learning purposes, you can even connect a LED directly to a pin without a resistor; 90% of the time, nothing bad will happen if you use just one port and one LED. Problems only appear when you use multiple LEDs and multiple pins without series resistors. [1, 2, 3, 4, 5]

Anyway, I highly recommend starting with the Arduino Nano because it is so cheap. For learning, buying 10 pieces is actually a great idea! If one breaks, you just swap it for another. If you are constantly afraid of breaking things, you will never learn! [1]

So, if you write digitalWrite(13, HIGH); in the Arduino IDE, or sbi 5, 5 in my program, without setting the pin as an output, the LED shines faint. But if you also add sbi 4, 5, the LED shines bright.

my original message:

i use 13 because is led onboard and already ha ve a resistor onboard! not need external led and resistor! Also you can put directly led on pin without resistor as didactic, in 90% of cases not suceed nothing if use only a port and only a led , problems appear when use more led and more pins without serial resistor. Anyway raccomand begin with arduino nano because cost is less , and for learn , buy 10 pieces , is not abad idea! when one not working change with another.because if you are fear to brocken ,not learn ever!

so if in arduino ide write digitalwrite(13,HIGH) or in my program sbi 5,5 without set pin as output the led faint, is put also sbi 4,5 led bright

Not my schematic, it's from the datasheet.
The raw truth is that the switch is NOT in parallel, it is in series.

So your explanation of how the IC actually works is wrong.

If you bypass the resistor by putting a parallel switch, the LED will face full 5V and will be damaged instantly! So, RHS diagram of your post #3 is not valid. The LHS diagram is ok as long the switch remains open.

To turn on the LED, you have again brought the concept of drawer and swtches which you have already covered in another thread. Now, let us talk with something else -- the new technology around STM32U585 MCU and QRB2210 MPU of the UNO Q board. May be, these two devices are turning on LED in different way than the AVR of UNO R3.

i did :

...The real process is more complex, but for learning purposes we can imagine that the final hardware action is equivalent...

so is only educational with some practical examples

but im curios from achematic if can draw a red line how il alimented led onboard when is input and how when is output!

can be interesting for principiants!

Then it is not the "raw truth inside the chip", it's just your misconception of how it works.

Whatabout input without pullup? Your "circuit" doesn't include that option.

if this is problem , and think that is not correct i can changed!

what proposed?

If you are actually trying to explain "inside the chip" then make your diagram to show the switch in series.

Come on, this is just a didactic guide for beginners, not a textbook for electronics engineers! Did you actually read what I wrote? Does this look like a highly technical datasheet to you? :wink: My goal is to lower the cognitive load and show the basic logic of the chip to people who are just starting out, without boring them with every FET, resistor, and logic circuit on the advanced schematic of the ATmega328.

ok , explain because led faint when pin is input and because bright when output?

Yes ,arduino can be damaged! This happens in reality if you set a pin as an output, set it to HIGH, and short it directly to ground (0V)!

But if you connect a LED from a pin straight to ground, it's not 100% guaranteed that it will get damaged instantly. It will just shine a bit brighter than normal. It's definitely not recommended, but for a quick test, you can do it—especially if you have 10 spare Arduinos in your drawer! :wink:

yes ... this happen in reality if put pin ouput , set to high and put at ground 0v!if put led a led from pin to ground is not 100% that damaged , will bright little more than normal , is not recomandat , pero per un test rapido si puo fare, anche se hai 10 arduino di scorta!

Anyway, explaining a pull-up to a beginner with this diagram seems a bit exaggerated!