---

Wednesday, December 18, 2024

The search for the built-in LED - ESP32

A recent question for me from a reader of my ESP32 book (thanks Richard) was: 

how do I find out which pin the built-in LED (if there is one) is connected to?

You'd think this would be a simple matter of consulting the documentation, but the documentation is very hard to find because there are so many different ESP32 development boards. They are often not even identified by a consistent name.

Pinout diagrams are fairly easy to find, but they do not usually identify the pin used for a built-in LED.


To help Richard out, I've come up with this test program to help in the search for the pin. 

The code

from machine import Pin
from time import sleep

pins = [x for x in range(0, 36)] # end of range last pin no. + 1
ignore_pins = [0, 1, 6, 7, 8, 11] # exclusions

pins = list(set(pins) - set(ignore_pins))

print(pins)

for pin in pins:
    try:
        print(f"Trying Pin {pin}")
        led = Pin(pin, Pin.OUT)
        led.on()
        sleep(0.5)
        led.off()
        sleep(0.5)
    except:
        print(f"Pin {pin} not allowed")


Usage

To use the program,  hold your board up in front of Thonny (or whatever you are running the code in) so that you will be able to see when the LED lights.

WARNING: This program will attempt to set every pin to be an output, so do NOT attach any extra electronics, and reset the board once you've finished testing it.

Run the program, and when the LED blinks, make a note of the pin that was being tested.

When you try and set a pin to be an output, this will either cause an exception (which we can catch) or cause the whole board to crash, or USB communication to fail (which we can't catch). So, if a certain pin seems to be causing a crash, add it to ignore_pins and try again.

Results

I tried this on a couple of boards, with these results. 

  • ESP32 Lite - 22
  • ESP32 Dev Kit 1 - 2

If you try this out and identify the pins used on a board,  send a comment (comments moderated, so it may take a while) or @simonmonk2 on X and I'll keep updating this list.



Monday, September 23, 2024

Are the Pico 2 (RP2350) GPIO pins broken?

TLDR; A little bit, yes, but it probably doesn't matter.

The new Raspberry Pi Pico 2 mostly represents a bump in performance and memory. 

A welcome feature of the release, for authors such as myself, is that the functioning of the GPIO pins and the pinout remains the same as the original Pico 1, as does the most used microPython programming environment,  

So, it was a surprise to find various reports of a hardware bug affecting GPIO pins. My main concern was, does this affect the way GPIO pins are used in the examples for my book Programming the Pico, as well as the instructions for our Pico electronics kit.?



The Problem

You can find the formal explanation of the bug in the RP2350's datasheet - on page 1341 (yup, perhaps don't start looking for it on page 1). The detail is somewhat complex, affecting only the situation where a GPIO pin (any) is used as a digital input with the internal pull-down resistor enabled.

Digital Input (Internal Pull-UP resistor enabled)

Before we look at the problem scenario, let's try out the more common situation where a GPIO pin is sued as a digital input with the internal PULL_UP resistor enabled.


Here is the example code (from Programming Pico).

from machine import Pin

from utime import sleep

switch = Pin(10, Pin.IN, Pin.PULL_UP)

while True:

    print(switch.value())

    sleep(0.1)

In this scenario, the internal pullup resistor is enabled by the line of code:

switch = Pin(10, Pin.IN, Pin.PULL_UP)

.. this keeps the GPIO pin (10 in this example pulled up to the 3.3V supply voltage, registering as a 1 when it's value is read. This resistor, that is built into the PGIO hardware of the RP2350, has a value of a few 10s of kΩ. When the switch is pressed, this relatively weak pull-up is overpowered as the switch connect the GPIO pin to GND (0V). The input then registers as a value of 0 when read.

When you run the program, you will see something like this.

By default, the value shown in the Shell area is 1, but when the switch is pressed, it changes to 0. Here's the breadboard layout using parts from the MonkMakes Electronics Kit 1 for Pico.


So, in short, this works just fine. No problem here.


Digital Input (Internal Pull-DOWN resistor enabled)

Some microcontrollers do not even have the option of a built-in 'pull-down' as opposed to 'pull-up' resistor. Generally switches on digital inputs connect the GPIO pin to GND (0V) when pressed. This is the safest option, as generally boards only have one GND of 0V, but may have several supply voltages (3.3V and 5V -- in the case of a Pico). Connecting 5V to a 3.3V digital input can destroy that input on may GPIO designs, so it's much safer to use pull-up resistors and cope with the inverted logic of 0 meaning pressed and 1 meaning not pressed in your code.

Having said that, the feature is there, so people will make use of it. So, here is the problem situation, of digital inputs with a built-in pull-down resistor.


This is shown on breadboard, here, where the switch is now between GPIO 10 and 3.3V on the Pico. There are also 2 more leads connected to a DMM acting as a voltmeter measuring the voltage at GPIO 10.



Here is the code. All that's changed is that Pin.PULL_UP has become Pin.PULL_DOWN

from machine import Pin

from utime import sleep

switch = Pin(10, Pin.IN, Pin.PULL_DOWN)

while True:

    print(switch.value())

    sleep(0.1)

When I run the program, there is immediately a problem apparent. The Shell is reporting values at the GPIO pin of 1. This should be 0, because the switch is NOT pressed and the pull-down resistor is enabled. The voltmeter is reading 2.11V, which is above the threshold for being a high input (reading a value of 1).

If I then press the button, there is no change to the output in the Shell, it is still saying 1, but the voltage at the PGIO pin is now 3.3V as you would expect.

So, if the GPIO acting as an input, actually suddenly looks like an output at 2.11V, how much current flows through the GPIO pin when we press the switch connecting it to 3.3V?!

Connecting the multimeter to the GPIO pin to measure the current drawn, then the answer is a reassuringly tiny current of just 60µA. So, we are not going to burn anything out.

So, in short, don't try and use the built-in pull-down resistors, they don't work. 

Conclusion

The internal pull-up resistor feature of digital inputs works just fine, but the pull-down feature does not work. I can live with that, because it's better practice to just use pull-up resistors.

So, should you buy a Pico 2? Yes, unless you really ned to use internal pull-down resistors.

Note that my Pico 2, was bought in September 2024, so you might find that this has been fixed in the silicon that you have.

Thursday, September 5, 2024

Jacdac - First Impressions

Jacdac is a modular prototyping/educational electronics system and protocol. This isn't Microsoft's first foray into this world. Some of you will I'm sure remember the .Net Gadgeteer system. 

In Jacdac, Microsoft have clearly learnt from their experiences of .Net Gadgeteer and produced an easy to use and more child friendly system, that can make use of the micro:bit, as well as other 'brains' using a selection of adaptors.

The Kit I was kindly given to play with is the Jacdac Starter Kit A, which is available from Amazon.com and elsewhere.

What's in the box?


The kit includes: 

  • push buttons, 
  • a rotary encoder, 
  • a slider (pot), 
  • a Neopixel (multicolor LED), 
  • a bundle of Jacdac leads,
  • a Jacdac micro:bit interface board,
  • a Jacdac expander (if you need more connections)
Each module (even a key-switch) has a tiny microcontroller to handle communication, as well as indicator LEDs that show connection and communication is working. 

Getting Started

To get started, I followed this tutorial. Note that this kit only works with version 2 of the micro:bit (the one with the bumpy edge connector).

Follow each step carefully. I hadn't noticed that the slide switch on the micro:but adapter was in the wrong position, This needs to be set to the position labelled Jacdac.

Follow the tutorial, but in overview the steps are:
  • Create a new Makecode project
  • Install the Jacdac extension
  • Download the new Makecode program onto your micro:bit
  • Start plugging stuff in

Connectors

The Jacdac connectors are reversible (like USB-c) and great for kids -- at least compared to wrangling open the jaws of alligator clip leads. The kit helpfully supplies a selection of lengths of lead.

The leads can be connected to any of the ports on the micro:bit adapter and can be daisy-chained together, making the wiring simple and un-cluttered.

If everything is setup correctly, then when you connect one of the modules to the adaptor, the module will appear in the left-hand side of the Makecode editor window.


Here you can see that Makecode has become aware of the Slider and LED ring devices.

You don't yet have any blocks you can use, but if you click on the ADD BLOCKS button, blocks for using the devices connected will appear in the Modules category of blocks in Makecode.

The screen capture above show a program that sets the brightness of the LED ring depending on the position of the slider.

Conclusion

Overall, I really liked using this hardware. The quality is excellent and leverages the already popular micro:bit and Makecode nicely.

Pros

  • Easy to use and child friendly
  • High quality

Cons

  • There is no concept of a circuit. It's modules plugged together. In extremis, you could just leave everything in the kit plugged together all the time. You are really just choosing which modules to use and which to exclude.
  • A little on the pricey-side. But, looking at the design, I can see why it has to cost what it does. 


Who's it For

I think, that as an educational tool, this is an excellent system. Kids and educators will have a lot of fun with this.

It may also have some use during product design, as a way of producing a functional prototype very quickly, allowing usability to be assessed.

Who isn't it for

I don't see this being used by electronics hobbyists and makers. It's too expensive to be used in permanent installation of projects. Arduino and clones coupled with solderless breadboard migrated onto soldered prototyping board are a more realistic prospect.

Even though it's good for making prototypes from a user interface perspective, it of no real value in prototyping an electronic design. No electronic engineer is going to couple a microcontroller with every LED or push-button in an embedded system.  

Monday, June 10, 2024

New Book on ESP32 and MicroPython

I've had several requests, over the years, from readers of my books for me to write a book on the ESP32. Yes, there is lots of information out there on the Internet, but it's nice to have everything in one place, and also tried and tested on a variety of ESP32 boards. So, somewhat late to the party, I've finally written one.


I've based the book on MicroPython using Thonny. Thonny helps a lot with the ESP32. Not only is it a nice simple Python editor for those new to coding, but it also integrates with the esptools software, making it easy to flash your ESP32 board with the MicroPython firmware, without having to use the command line.


One of the biggest challenges in writing a book about ESP32 is the shear number of different ESP32 boards available.


This book is two-thirds Python programming, which applies to and ESP32 board and one third electronics using solderless breadboard. When it comes the electronics side of things, I provide breadboard layouts for two of the most popular ESP32 boards, the ESP32 Lite and the DevKit 1.


The paperback version of the book is printed in monochrome to keep the costs down, but a color ebook version is also available.

The book is available on Amazon.com.


In the future it will also be available from some of MonkMakes resellers and you can find details, here:

https://monkmakes.com/book_prog_esp32

All the example code is available on github here. https://github.com/simonmonk/prog_esp32

The books webpage is here: https://simonmonk.org/esp32



Monday, April 1, 2024

ESP32 Programmable Output Current - LEDs without resistors?

I'm currently in the final stages of a new book 'Programming the ESP32' and while browsing the MicroPython documentation for the ESP32, I came across a section describing setting the output current of an ESP32 GPIO pin. This implied that by including this in your code: 

p6 = Pin(32, Pin.OUT, drive=Pin.DRIVE_3

you could set the drive current of a GPIO pin to 40mA - perhaps enough to directly drive an 8Ω speaker to quite a high volume. 

Or, by doing this: 

p6 = Pin(32, Pin.OUT, drive=Pin.DRIVE_0

you could limit the current to just 5mA and drive an LED directly without the need for a current limiting resistor. 


Background

The GPIO (General Purpose Input Output) pins on a modern microcontroller are little marvels of configurability. In software, you can configure them in various ways:
  • as an input or output
  • if acting as an input enable pull-up or pull-down resistors to bias the input high or low respectively
  • route a pin to an ADC (analog to digital converter) to act as an analog input and measure voltage
  • route a pin to a capacitative touch detector
  • route pins to special bus interfaces I2C, SPI and UART
When acting as outputs, GPIO pins have what are called complimentary outputs. That is, current can flow from the pin through something (say an LED and resistor) to GND -- called 'sourcing' or, you can connect one end of the load to the +3.3V supply and 'sink' current through the GPIO pin.

It looks like the ESP32 takes this a step further and allows you to set the maximum source or sink current for a GPIO pin in your code.

Goals of the experiment

Note that there is a big difference between good professional design practice and hobbyists messing around. A proper electronics engineer would never try to 'get away with things' in the way that I am here.

So, anyway, here's what I hoped to find out, using a low-cost ESP32 Lite board. After all there's a good chance this testing will end in the destruction of the board, so it might as well be a cheap one.
  1. Do these drive current settings actually control the DC current limiting of the GPIO pins?
  2. Does this current limiting also amount to short-circuit protection for GPIO pins?
  3. How much current can I draw from an ESP32's GPIO pins before I kill it?
  4. Can I use an LED without a current limiting resistor?

Method

Rather than jump straight to potentially destructive short-circuit testing. I began with the setup below, using a 100Ω resistor load to provide current limiting to I=V/R = 3.3/100 = 33mA. 

With the DMM set to a current range, the resistance across its leads will be close enough to 0Ω to ignore in these tests. From the MicroPython documentation here are the different drive currents. Our 100Ω resistor won't allow us to go to the maximum 40mA, but we can at least get an initial view of any current limitting.

  • Pin.DRIVE_0: 5mA / 130 ohm

  • Pin.DRIVE_1: 10mA / 60 ohm

  • Pin.DRIVE_2: 20mA / 30 ohm (default strength if not configured)

  • Pin.DRIVE_3: 40mA / 15 ohm

Results

GPIO 32


100Ω resistor load




Setting in Code

Nominal current (mA)

Measured Current (mA)

Pin.DRIVE_0

5

10.5

Pin.DRIVE_1

10

18.3

Pin.DRIVE_2

20

24.4

Pin.DRIVE_3

40

28


So, the current is about twice what was expected - at this point, I thought I might have an 'out-by-1' problem with my code (see the end of this post) but the code looks ok.

Nothing got hot, so I dispensed with the resistor and jumped to effectively short circuit testing, with the DMM ammeter connected directly between the GPIO and GND as shown below




Here are the results for this short circuit test.

GPIO 32

short cct





Setting in Code

Measured Current (mA)


Pin.DRIVE_0

10.9


Pin.DRIVE_1

22.6


Pin.DRIVE_2

44.6


Pin.DRIVE_3

84.9



Wow, so nearly 85mA from a single GPIO pin shorted to ground. I checked the ESP32 chip and using the finger test scale of: ambient, warm, hot, ouch, we were definitely 'warm'. Leaving the setup at DRIVE_3 for 90 minutes, there was minimal change in current or temperature of the ESP32.

Deciding to push my luck, I next tried 2 GPIOs in parallel at DRIVE_3, and modified my code to set the drive mode for all 2. Using pins 32 and 33, the current rose to 152mA and the ESP32 chip was still only warm.

Next, I tried adding GPIO 35. This made no difference to the current, nor for that matter did GPIO 34. However when I used GPIO 27 instead the current leapt to 220mA. I left this running for 30 mins and while the temperature increased to 'hot' it didn't get anywhere near 'ouch'.

I didn't push it any further, but instead tried some LEDs using the lowest current setting DRIVE_0. 

Red 8.4mA, Green 4.6mA, Blue 4.1mA. All lit nicely.

What Does the Datasheet Say?

The datasheet for the ESP32 is pretty vague about the GPIO pins. I couldn't find anything about the programability of current limiting. Searching for 'current' I came across this implying that 40mA was fine:


and also this:


The note 1. is staggering! 1.2A of GPIO power! 

Conclusion

Q1. Do these drive current settings actually control the DC current limiting of the GPIO pins? 
A. Yes - and it seems to work pretty well, even with a GPIO short-circuited.

Q2. Does this current limiting also amount to short-circuit protection for GPIO pins?
A. Yes.

Q3. How much current can I draw from an ESP32's GPIO pins before I kill it?
A. Well, it coped with 220mA from 3 GPIO pins without a problem.

Q4. Can I connect an LED without series resistor.
A. At the lowest current setting, I don't see any problem with connecting an LED directly to GPIO pins.

Also, the current limiting features of the GPIO pins means that it's relatively safe to parallel up multiple GPIO pins. If you were designing a product, then I wouldn't do this, but I'd be really tempted for a home project.

The caveat in all this is that without something documented in the datasheet there are no guarantees about how stressing the GPIO pins hard will affect the lifespan of the ESP32.

Test Program

Here's the test program I used for a single GPIO pin.


from machine import Pin

pin = 32

currents = [
    {'drive': Pin.DRIVE_0, 'mA': 5},
    {'drive': Pin.DRIVE_1, 'mA': 10},
    {'drive': Pin.DRIVE_2, 'mA': 20},
    {'drive': Pin.DRIVE_3, 'mA': 40},
    ]

while True:
    print('(0) 5mA, (1) 10mA, (2) 20mA, (3) 40mA')
    index_str = input('enter number 0 to 3: ')
    try:
        index = int(index_str)
        p = Pin(pin, Pin.OUT, drive=currents[index]['drive'])
        p.value(1)
        print('current set to mA: ' + str(currents[index]['mA']))
        print()
    except:
        pass

And here's the code for a lit of GPIO pins in parallel

from machine import Pin

pins = [32, 33, 27]

currents = [
    {'drive': Pin.DRIVE_0, 'mA': 5},
    {'drive': Pin.DRIVE_1, 'mA': 10},
    {'drive': Pin.DRIVE_2, 'mA': 20},
    {'drive': Pin.DRIVE_3, 'mA': 40},
    ]

while True:
    print('(0) 5mA, (1) 10mA, (2) 20mA, (3) 40mA')
    index_str = input('enter number 0 to 3: ')
    try:
        index = int(index_str)
        for pin in pins:
            p = Pin(pin, Pin.OUT, drive=currents[index]['drive'])
            p.value(1)
        print('current set to mA: ' + str(currents[index]['mA']))
        print()
    except:
        pass


Wednesday, January 24, 2024

Lies, Damn Lies and Analog Inputs (comparing ADCs on ESP32, Pico and Arduino)

After some inconsistent and unreliable results reading an analog input from an ESP32 board, I decided to get all scientific and do some experimenting with an ESP32, a Raspberry Pi Pico and an Arduino Uno R3.

Method

My test setup was a bench power supply providing the reference voltage to be measured by the test board. The output of the bench PSU had a dummy load of a 470Ω resistor and a 100nF capacitor in parallel (the latter largely for superstitions reasons) as the voltage output looks extremely stable on a DMM voltmeter.

This output from the bench power supply was then applied directly to an analog input and GND of the board being tested.

I was particularly interested in three things:

* finding any dead-zones at each end of the analog input voltage range

* measuring the reproducibility of the readings

* linearity through the range

Another time, I'd like to look at the input impedance of the ADC (analog to digital convertor) and the effects of how rapidly you sample. But I'll leave that for another day.

To measure the reproducibility of the readings, each time the test voltage was changed, 100 readings would be taken, and the mean and standard deviation of that set recorded. That way, when it came to plotting the readings from the boards, I could add some error bars.

For the ESP32 and Pico, I used MicroPython and for the Arduino Uno, I used Arduino C. The Arduino readings were scaled up to 16bit unsigned values (max value 65536) to be consistent with the MicroPython version. In all cases, the default ADC settings were used.

ESP32

For this experiment, I used an ESP32 Lite (sometimes also called LOLIN32 Lite). These are a ubiquitous low-cost ESP32 board, with built-in WiFi and Bluetooth.

Analog input maximum voltage 1.0V



Here's the plot

The red error bars show +- 3 standard deviations (SDs) from 100 samples. Nearly all of the sample values would fall within 3 SDs and 60% would fall within 1 SD.

There is a sizeable dead zone until the voltage rises to about 0.05V and a lot of noise around the readings, evidenced by the large error bars. But it retains pretty good linearity once you get past that up to the 1V upper limit.

Raspberry Pi Pico

The Raspberry Pi Pico uses Raspberry Pi's RP2040 chip. It'a another popular, good value board.

It's maximum analog input voltage is the full 3.3V supply range.


Here's the plot for the Pico - 


This is considerably better than the ESP32, with smaller 3 x SD error bars, a small dead zone at the low voltage end and some slight tail-off in linearity at the 3.3V end.

Arduino Uno R3

Despite its age, the Arduino Uno R3 (not the fancy new one) is still my go-to board for any experimentation or early stage project work that doesn't need a specific microcontroller. I'll admit, it's partly out of familiarity and inertia on my part.



And here are the results.


And there we have it. Very little deviation between readings and great linearity across the whole range, right up to 5V. The Uno with it's ancient Atmega328 is streets ahead of the other two boards.

Conclusion

On looking at the documentation in MicroPython and learning that the analog readings for a Pico and ESP32 come at a massive 16 bit precision (a number between 0 and 65536) it's easy think that their analog inputs are much better than the paltry 10 bits of an Arduino (0 to 1023 reading range). But this is to confuse precision with accuracy. It's why pure megapixels is not the best way to judge a camera. So much depends on the lens.

So, if you are trying to get decent accuracy and reproducibility from your analog readings, then you probably want to take a set of readings and average them -- or use an Arduino Uno R3!

Test Programs

ESP32

from machine import ADC, Pin
from time import sleep
from math import sqrt

analog = ADC(12)

p = 0.05
n = 100

while True:
    readings = []
    for i in range(0, n):
        readings.append(analog.read_u16())
        sleep(p)
    total = 0
    for i in range(0, n):
        total += readings[i]
    mean = total / n
    dist_tot = 0
    for i in range(0, n):
        dist = readings[i] - mean
        dist_tot += dist * dist
    
    print(mean, sqrt(dist_tot / n))
    
    input('Press enter to read again')

Pico

from machine import ADC, Pin
from time import sleep
from math import sqrt

analog = ADC(28)

p = 0.05
n = 100


while True:
    readings = []
    for i in range(0, n):
        readings.append(analog.read_u16())
        sleep(p)
    total = 0
    for i in range(0, n):
        total += readings[i]
    mean = total / n
    dist_tot = 0
    for i in range(0, n):
        dist = readings[i] - mean
        dist_tot += dist * dist
    
    print(mean, sqrt(dist_tot / n))
    
    input('Press enter to read again')

Arduino

int p = 50;

const int n = 100;


unsigned int readings[n];


void setup() {

  Serial.begin(9600);

}


void loop() {

  if (Serial.available()) {

    Serial.read();

    Serial.println("measuring");

    for (int i = 0; i < n; i++) {

      readings[i] = analogRead(A0) * 64; // 16 bit not 10

      delay(p);

    }

    float total = 0.0;

    for (int i = 0; i < n; i++) {

      total += float(readings[i]);

    }

    float mean = total / n;

    float dist_total = 0.0;

    for (int i = 0; i < n; i++) {

      float dist = float(readings[i] - mean);

      dist_total += (dist * dist);

    }

    float sd = sqrt(dist_total / n);

    Serial.print(mean); Serial.print(' '); Serial.println(sd);

  }

}



Wednesday, September 27, 2023

Raspberry Pi 5 Review

I was lucky enough to get hold of a pre-release Raspberry Pi 5. Here are my impressions of this latest incarnation of the Raspberry Pi Single Board Computer.



First Impressions

The first thing to strike me was the almost minimalist PCB layout, the top-side being mostly big chips with a lot of the tiny little capacitors and resistors on the underside of the board.

Reassuringly, the 40 pin GPIO connector fixing holes and usual great selection of USB and HDMI morts on the Raspberry Pi are all still there.

My version was supplied with an Active Cooler kit. One criticism of the Pi 4 was that it did tend to get quite hot. The complex self-monitoring of the SoC (system on a chip) meant that the hardware was not in danger, but it's a little disconcerting when the top surface of the chips feel like you could fry an egg on them. (I exaggerate!).

So a little fan to keep things cool will allow the Pi 5 to run at full speed.



The 'Active Cooler' is simplicity itself to fit. You just peel off the backing paper from the heatsink pads and push two sprung-loaded plastic pegs through holes on the board for that purpose. It makes the Pi 5 look pretty badass!


However, with the Active Cooler attached, there is very little room between the edge of the heatsink and the GPIO pins. This means that GPIO templates like the Raspberry Leaf are not going to fit. So anyone wanting to use the GPIO is going to be back to counting pin positions. 

Specifications

The Pi 5 is between two and three times faster than Raspberry Pi 4 (itself no slouch). It has a 64-bit quad-core Arm Cortex-A76 processor clocked at 2.4GHz. This time using a SoC designed by the Raspberry Pi team themselves.

Raspberry Pi 5 also offers significantly improved graphics performance and camera support, and some neat little extras:

  • A connector for a fan.
  • A connector for a backup battery, allowing time to be kept on the Real-time clock. (In most situations, this isn't really very useful as the Pi will set its clock from the internet. However for offline applications, this could come in handy.
  • A connector for UART (serial interface)
  • a PCIe 2.0 connector (for attaching SSDs etc)
  • A Reset switch
The Pi 5 is available with either 4 or 8 GB of RAM.

Who's it for?

The Raspberry Pi 4 was already a very worthy desktop/laptop replacement. At MonkMakes, we use the closely related (to Pi 4) Pi400 as a very capable office machine. With the increase in performance of the Pi 5 and with the edition of a PCIe SSD and a sturdy little case, then this device can replace a laptop or desktop computer in many situations. I sincerely hope that a Pi 500 built into a keyboard will be coming along soon.

This Pi is much more about being a proper computer, and I wouldn't be surprised to see the GPIO pins to eventually disappear altogether in some future version. 

Verdict

Top marks as a desktop replacement at a very competitive price. As a Single Board Computer (SBC), the huge community and availability of resources and add-ons make this (IMHO) the best SBC option.

However, if you don't need the performance, and are more interested in doing things with GPIO pins than you are browsing the internet or watching videos, then stick with a Pi 3. They use much less power and are perfectly adequate for most embedded applications, and you can attach a GPIO template so you know which pin is which.

For more information, see the official Raspberry Pi announcement.