---

Monday, September 1, 2025

Switching explained -- MOSFETS vs. SSR ICs vs. Electromechanical Relays

There are a lot of options when it comes to using your favourite microcontroller (be it an Arduino, Pico, ESP32 or micro:bit) to switch something on and off. In this post I will compare some of the various options available.




Option 1. Direct connection to GPIO pin

It's quite common to connect LEDs (usually with a series resistor to limit the current) directly to the GPIO pin of a microcontroller. Pretty much any microcontroller will let you draw up to 5mA (enough for an LED to light) some (Arduino Uno for example) will let you draw tens of mA without any problem, and some like the ESP32 can be configured for really quite high currents (85mA) see my earlier post on this.

However, even datasheets can be vague about things like total current budgets for all GPIO pins. So, if you are making something for fun, by all means push the boundaries of your GPIO pins and in the worst case, be prepared to replace your microcontroller.

Using the GPIO pins directly also limits the voltage you can switch to the microcontroller's supply voltage and whatever you are switching will share that supply which could lead to problems with electrical noise.

If, on the other hand, you are making a product or need a robust reliable design for other reasons, then you should probably move on to the options that follow.

Option 2. Low-side MOSFET Switching

Here is the basic schematic for using an N-channel MOSFET as a 'low-side' switch. It's 'low-side' switching because the lower voltage end of the load is switched to ground (GND) allowing current to flow through the load powering the load as the current flows to ground through the MOSFET. 

Low-side switching is more common than 'high-side' because the MOSFET is turned on and off using a voltage relative to ground rather than +V. So 'high-side' switching of voltages above the logic level would need an extra transistor, or specialised MOSFET gate-driver IC. 
Once the voltage at the MOSFET's gate exceeds the threshold voltage (usually a couple of V) the MOSFET will conduct.


You may be wondering, about R1 and R2. Let's look at these in turn:

R1. Do you need a resistor R1 between the GPIO pin and the MOSFET's gate? Well, the thing is, the MOSFET's gate looks to the microcontroller like a capacitor to GND, in the schematic above, so when the voltage is first applied to the gate when the GPIO pin goes high, current will rush into the capacitor filling it up. A typical MOSFET might have a maximum equivalent capacitance less than 1 nA. Including a resistor slows the charging of the gate capacitance, reducing the peak current. Most GPIO pins are very tolerant of very short duration currents and in any case, there will be come resistance in the form of PCB tracks and wires between the GPIO pin and the MOSFET. So, while it is good practice to include R1 of perhaps 1kΩ. For hobby designs, you are unlikely to have problems if you omit R1 entirely.

R2. Which might typically have a value of 100kΩ pulls-down the gate to GND, keeping the MOSFET off. Again, the need for this may not be immediately obvious.

Imagine the situation where the MOSFET is controlling a high-power motor. If your microcontroller GPIO pin, rather than being an output, was configured by accident as an input, then the gate of the MOSFET would be 'floating'. Just touching the track connected to the gate would likely be enough to turn the MOSFET on. Most likely, your body would act as an antenna, picking up AC electrical noise at 50Hz or 60Hz depending on where you live. This will be turning the load on and off 50 times a second without any control from the microcontroller. Another scenario where the gate could be left floating would be where the MOSFET and microcontroller were on separate PCBs joined by a connector that might be unplugged to leave the gate floating. In any case, a 100kΩ resistor for R2 will make things safe, and will be easily overpowered by the GPIO pin when it goes high to turn the MOSFET on.

By now, some of you may be screaming "WHAT ABOUT BIPOLAR TRANSISTORS?". My answer is "Meh!". To elaborate on this a little. Yes you can, but when it comes to switching, I prefer to stick to one type of very cheap transistor, rather than two types of very cheap transistor. And for me that's an n-channel MOSFET.

The thing is, for low currents an NPN bipolar transistor is fine, but as the current you are switching increases, you need more current to turn them on and they start to get hot.

If you are using a MOSFET, switching is essentially voltage not current controlled and as the current you are switching gets higher, all you need to do is buy a MOSFET, for a few cents more, that has a lower on-resistance.

For example, the MOSFETs used in the popular MonkMakes MOSFETTI board and the Switch for micro:bit (see below) only cost a few cents each, but can switch 3A at 60V, with an 'on' resistance of just 0.1Ω they barely even get warm most of the time.




Referring back to the schematic, it is important to note that, although the MOSFET 'turns-on', it is not a pure switch. By 'turning on' we mean that it will allow a current to flow (confusingly) from the drain to the source, but NOT the other way around. So we have to be aware of the polarity of the supply voltage.

Option 3. Electromechanical Relay

A traditional relay is an electromechanical device that uses an electromagnet to actually move a pair of contacts. When a current of a few tens of mA flows through the coil, it pulls the contacts together making an electrical connection, just as if you had flipped a switch. The important thing here is that there is NO electrical connection between the coil and the contacts. 




The contacts are free to operate at a different voltage and switch a completely different circuit to whatever the coil is controlled by (typically a GPIO pin of a microcontroller (using some extra circuitry)). Electro-mechanical relays are cheap, but switch slowly and require quite a high current through the coil to activate them. This means that generally you should use a MOSFET or bipolar transistor to switch the current to the coil. In fact you could use the MOSFET example above to drive the relay coil.

Low-cost relay modules such as the one shown below, have this extra circuitry built-in.


Option 4. Solid State Relay ICs

In many ways, it is amazing that electromechanical relays are still in use. For low voltage, low current applications, they can be replaced a a solid state relay IC. These chips behave just like an electromechanical relay, but without an moving parts.


Instead of a coil they have an LED, that is optically coupled to a pair of MOSFET phototransistors. So that when the LED is energised (only requiring a couple of mA) the MOSFETs turn on. The MOSFET pair are arranged in such a way as to be able to switch low-voltage AC or DC. The schematic above is take from the MonkMakes Dual Relay, which has two such relay chips on a single board.





The advantage of a SSR over an electromechanical relay, is that you can use Pulse Width Modulation with an SSR to perhaps control the brightness of an LED lamp or the speed of a motor. It's not wise to try and do this with an electromechanical relay, as opening and closing the contacts rapidly wouldn't be fast enough for say dimming an LED lamp, and would soon ware-out the contacts.

Making a Choice

Use Option 1. Direct connection to GPIO pin -- if you are only switching a few mA of load and you know your microcontroller's GPIO can handle it, and you are switching a voltage that is the same as the microcontroller's supply voltage.

Use Option 2. Low-side MOSFET Switching -- if you are in control of the design of the load being switched and you know that it's ok for it to share a ground with your microcontroller. In other words, no electrical isolation between the microcontroller and load is needed. 

Use Option 3. Electromechanical Relay -- if you do NOT need PWM and you do need electrical isolation between the microcontroller and the load. Also, electromechanical relays usually have both normally-open (N.O.) and normally-closed (N.C.) contacts, which can sometimes be useful.

Use Option 4. Solid State Relay -- if you might need PWM and need electrical isolation between the microcontroller and the load.



Thursday, May 1, 2025

Tuesday, April 15, 2025 Accessible FM Radio Case Study - Part 3 - Audio Tests

[Part 1] [Part 2] [Code and Design Files]

After some promising results with the PCB loop antenna, in this post, I'm starting to look at the audio output.

The intention for the final system is to design a single PCB incorporating the power supply, radio receiver, power amplifier and antenna. But before launching in to this, I want to do as much testing and developing as possible using the modules that I have to hand.

In Part 2 I was getting reasonable signal strengths from the PCB antenna, but I hadn't really listened to the reception, except through headphones.

The TEA5767 module I used has an audio amplifier built-in, but its the now obsolete TDA1308 which is a stereo amplifier offering 80mW at 32Ω per channel. No good for driving a speaker directly.

To try out what I have so far, I had a rummage around and found an old version of the MonkMakes Amplified Speaker and connected it to the output of the radio module and to the 5V supply of the Arduino.


I was not expecting results. The Amplified Speaker, is a very low power quite tinny thing and the quality was pretty awful. Key point were:

  • Terrible sound quality
  • Significant hiss
  • Clicks every time the Serial Monitor reported the signal strength.
Touching the antenna to increase the signal strength got rid of the hiss. I am not too worried about this, as the FM reception at our house is pretty bad. Window-sills being required even for really good FM receivers.

The USB interference is not be a problem for the final device, as it will be battery powered, but it does serve as a warning that interference could well be a problem for the future.

I wanted to make sure that the TEA5767 output wasn't inherently low quality, so I connected the audio out of the TEA5767 module to the line-in of HiFi. The results were very acceptable. The USB click was still there, but overall reception was better (slightly different position).

Looking at datasheets and browsing component catalogues, I quite like the look of the PAM8320. It's a class D (think PWM) amplifier that can provide up to 20W. I don't need anything like that much power, but having some oomph in reserve is usually a good thing.

I think its getting close to the time, where I start to design the system as a whole.

Tuesday, April 15, 2025

Accessible FM Radio Case Study - Part 2 - PCB Antenna

[Part 1] [Part 3] [Code and Design Files]

In the first part of this series, I looked at the overall requirements for the project. A key one of these was to avoid the need for the classic 1/4 wave telescopic antenna, which is, something of a hazard.

Cars haven't had telescopic antenna for some time now. It turns out they are generally a conductive trace built into the car glass. (Not much use for this project). However, I had noticed the 'shark-fin' antenna on the top of cars. It seems, that according to this research paper. It is possible to make a compact PCB antenna suitable for receiving FM broadcast transmissions in the normal range of 88-108 MHz.

PCB antenna design

The research paper gives a detailed design for the PCB, including all dimensions. I have recreated this in KiCAD and you can find the design files and even generated CAM files for production in the github repository for this project.


The PCBs came back from JLCPCB and looked good, so I made a couple of the boards up using the surface mount components specified in the paper. You can see the values in the picture above.

I actually made up 2 boards, one with the intended SMA co-axial connector, and one using a chopped off end of a 3.5mm audio connector, to make it easy to connect the antenna to the TEA5767 board that I was using for testing.


I used a hot glue gun to stick down the audio lead to prevent the wires pulling off.



TEA5767 Module

As a first test of the feasibility of using this type of PCB coil antenna, I used the TEA5767 module shown here.


There are two 3.5mm headphone style sockets on the board. One is for stereo output, and can directly drive headphones and the other is for attaching an antenna. 4 header pins provide power and the 2 I2C bus lines.

The module has an I2C interface that I will control using an Arduino Uno. The I2C interface allows you to set the tuning and volume, but also, crucially allows you to obtain the signal strength.

I can use this to compare the performance of the antenna against other antenna options, by tuning to a known radio station and then switching antennas.

The TEA5767 module is also 5V operation so I can connect it directly to the Arduino Uno and use the Arduino to power it.

The wiring is as follows:

  • 5V on the Arduino (red) to Vcc on the radio module.
  • GND on the Arduino (blue) to GND on the radio module.
  • SCL on the Arduino (yellow) to SCL on the radio module.
  • SDA on the Arduino (orange) to SDA on the radio module.


You can find the Arduino test sketch here.

/*
 * Modified from original library and examples by big12boy 2017
 * https://github.com/big12boy/TEA5767
 * 
 * Mostly reformat and recomment and simplification.
 * 
 * Signal strength only updates if you do a reset. Use Arduino Reset button
 * 
 * Tested on Arduino Uno connected to TEA5767 module. 
 * 
 * This used to test TEA5767 basic operation and measure signal strength for various antenna.
 * 
 * See blog post here for more detail: 
 * https://www.doctormonk.com/2025/04/accessible-fm-radio-case-study-part-1.html
 * 
 */

#include <TEA5767.h>
TEA5767 radio = TEA5767();

float frequency = 93.0; // Enter your own Frequency in MHz. Look up the frequency of a station near you. 
long baud = 9600;       //Enter your own Baudrate. I always use 9600.

void setup() {
  Serial.begin(baud);
  Wire.begin();
}

void loop() {
  radio.setFrequency(frequency);
  printReady();
  printStereo();
  printSignalLevel();
  
  Serial.println();
  delay(1000); 
}

void printReady(){
  int rdy = radio.getReady();
  Serial.print("Ready: ");
  Serial.println(rdy);
}

void printStereo(){
  bool stereo = radio.isStereo(); 
  Serial.print("Stereo: ");
  Serial.println(stereo);
}

void printSignalLevel(){
  short level = radio.getSignalLevel(); 
  Serial.print("Signal (0-15): ");
  Serial.println(level);
}

Before running the program on your Arduino, change the line: 

float frequency = 93.0;

to a frequency of a station that you can receive strongly with an FM radio. In my case, this is BBC Radio 4.
When you open the serial monitor in the Arduino IDE and set the baud rate to 9600, you should see something like this:


You can, of course, plug some headphones in to the radio module to hear how much noise is accompanying the signal.

Test Results

Trying to keep all other things constant, the antenna options I measured, were:

  • No antenna, sig strength 0/15
  • 23cm telescopic antenna, sig strength 4/15
  • PCB antenna, sig strength 8/15
On listening to the audio on headphones, the quality was quite reasonable with only a little hissy noise.

This is really good news, and I'm hoping we can do without the telescopic antenna.

In Part 3 of this series, I'm going to start looking at audio amplifier and speaker options, as this will inform decisions about the power supply.

Friday, April 11, 2025

Accessible FM Radio Case Study - Part 1

In this series of blog posts, I am going to document my journey (which I am about to start) in designing a FM Radio receiver for which I have the very specific requirement of being usable by my brother, who suffered a stroke a few years ago. This has left him with cognitive impairment and use of just his left arm.

This blog will effectively form my notes, and follow my usual design process which is:
  1. Investigate technologies
  2. Create 'spike' examples to de-risk various aspects of the design
  3. Breadboard or strip-board prototype
  4. Testing
  5. Prototype PCB creation
  6. Enclosure and user testing
As I hope this will end up in a design that will help others, I am going to release all the CAD and firmware files under an open license. 


User interface

  • Volume control - rotary, a pot, therefore with absolute positioning and no turning down to silent.
  • On/Off switch - probably a stylish toggle switch, but low physical resistance and ok for one handed operation without having to hold the radio.
  • Three preset buttons. Real switches with an indicator to see which is selected. Obvious icons (probably on paper) to select the channel. Talk (BBC Radio 4), Classical (BBC Radio 3), Pop (BBC Radio 2).
  • A separate interface (behind a panel - or using a BLE phone app) to configure stations

Other requirements

  • Large capacity LiPo battery power
  • USB charge and pass through
  • Decent power amplifier and speaker
  • FM broadcast receiver (*)
  • Bluetooth audio for wireless headphones
  • No eye-pokey antenna
  • Stable enclosure (one-hand friendly)
* Why FM rather than DAB or Internet Radio. Well DAB is power hungry and offers no real advantage (except perhaps future-proofing) over FM. 

As for internet radio? Well, this was my first thought as it solves the antenna problem. However, when I have looked at this before, it's quite difficult to get stable URIs for station streams, especially for BBC stations, which is likely all my brother will listen to.

Looking at what was commercially available, I found this


Which is actually pretty close to what I was planning. And if all else fails, I could easily see myself getting one for my brother. However, although you can't see it here, it has an eye-poker antenna and is powered by D-cells. Neither of which I am keen on.


Technologies

At the moment, my initial list of technologies to experiment with includes:
  • A PCB antenna (as used in 'shark-fin' car antenna) -- this is the big risk, and subject of my next blog post.
  • The  RDA5807M radio receiver IC (I might also try TEA5767 to see which is more sensitive)
  • An ATTiny1614 microcontroller 
  • A power amp probably D-class. Ideally 10W or more
I've ordered some RDA5807M modules from Aliexpress and started designing a PCB FM broadcast antenna using the research paper I found. I will need both the radio module and the PCB antenna for my first experiments.

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.