ESP32-Cam Antenna Workaround

A while ago I got my hands on a pair of ESP32-Cam modules. They were crazy cheap and it looked like I had a great little device that would work well as a security or wildlife cam:

It’s tiny!

It was easy to program using the Arduino IDE and the example program, but no matter what I tried changing in the program it wouldn’t connect to my home wireless network.

There’s a lot of documentation out there on the ESP32 devices, but there are parts that seem to be missing. I wish I’d bookmarked the link, but I came across the comment section of one article that mentioned a 0R surface-mount resistor that selected the external antenna jack or the on-board PCB antenna. It didn’t take too long to find, and it was set to use the external antenna jack:

That explained why it wasn’t talking to the wireless – no signal. I could fix the problem in two ways: plug in an external antenna, or move the tiny little resistor so that it connected the ESP32 to the PCB antenna. I don’t have any connector that will fit that jack, so I decided to move the resistor.

**NOTE** Doing any combination or number of the following steps will definitely, POSITIVELY void the warranty of the device. It may also increase the electrical noise produced by the unit and/or its susceptibility to other sources of electrical noise. It may also cause operational or stability problems. It may also cause the device to produce wifi signals that are more powerful than allowed by law. Proceed at your own risk.

Unfortunately, between not being able to see it very well (even with a magnifier lamp), having a soldering iron with too large a tip, and having tingly fingers and shaking hands, I ended up with this:

Not only did I not manage to solder the resistor in place, I also ruined the PCB pad that connected back to the ESP32.

By this point I was getting pretty frustrated. Actually, I don’t think I’ve been that frustrated in quite a while. Fortunately, I had another ESP32-Cam that I could apply the knowledge that I gained on this one and not make the same mistake twi-bahahahaha… yeah, I ruined that one, too.

The two of them together cost me less than $15, but I hate throwing something out when it’s still “alive” (they both still booted and tried to connect to the wifi), and I was looking forward to playing around with them. Seeing as how they were pretty much garbage at this point anyway, I figured I’d see if there was anything I could do to get them working.

**NOTE** See previous note. Seriously.

I could see the PCB trace leading under the metal can, so I figured that if I was careful, I might be able to remove the can and find another soldering point to attach an antenna.

To remove the can, you don’t need a hacksaw or a Dremel… just a pair of very fine-tipped pliers or snippers. there is a small hole in the can in the inside corner right by where the antenna selection resistor pads are. Carefully grab it with the pliers/snips and pull straight upwards to make some room:

Slide the pliers in a bit more and lift up and away from the PCB antenna (towards the top of this picture). It may take a bit but the can end by the PCB antenna should break away:

Reposition and pull the can up and to the left – the right side and top should come free easily as well:

Reposition again and the last bit should break away with very little force:

The antenna connection point is – very nicely – right by where the antenna selection pads are, right between two surface-mount components with big pads and lots of solder:

So now to make the antenna. I used a piece of 26ga solid wire-wrap wire, but anything nice and thin will do 22ga is too big.

Cut a piece about 6.5cm long, then strip about 1-1.5mm and bend the stripped part at a right angle. Tin the wire, make sure it’s got a good coat of solder on it:

Bend the insulated part of the wire to whatever shape and angle helps you hold the stripped part in place at the new attachment point. Use the iron sparingly – if you’re heating and heating and it doesn’t seem to be melting, back off, give it a minute, and change your angle before trying again.

If you’re careful and lucky, you’ll end up with something like (or much better than) this:

Gently bend the antenna into the orientation you prefer, and you’re done!

Reminds me of one of those facehuggers from Alien

The next thing to try is powering it up (unless you haven’t programmed it, in which case you should probably do that now). With no can and a crappy detuned wire antenna, the ESP32-Cam was able to finally connect to my home wireless network:


And the camera’s video streaming works like a charm:

I suppose that instead of hanging a wire antenna off that point, I could’ve run a jumper from the new attachment point to the pad that connected to the PCB antenna (or the antenna jack, for that matter), but a) I just thought of it, and b) I don’t mind the crappy antenna look.

Portable Power For The GQRX Pi 4

I’ve been enjoying finding and listening to all kinds of stuff with the SDR, and since I got it working with the Pi 4 I’ve wanted to use it without needing an extension cord.

I had a lot of trouble finding a battery supply that would do the trick. I have a few of those USB power packs at home and tried them but the Pi kept reporting low voltage.

I then turned to putting a regulator on a 12V SLA battery. Unfortunately, even with capacitors and shielding, the switching regulator I tried put out a lot of noise that the SDR picked up. I knew a linear regulator would be quieter but as I suspected, it only took about a minute before the biggest heatsink I had was too hot to touch.

So… I went back to the USB battery packs.

There are a few problems with those packs. They can also be noisy (there’s switching circuitry in them too), they can sag under load, and most of the USB cables out there are cheap crap that use very thin wire.

I put a load (actually, a Pi 2) on each pack and watched what happened to the noise and voltage on the oscilloscope. The best of the lot turned out to be an older Anker Astro E4 13000mAh unit that held a pretty constant 4.92V and wasn’t too noisy. So I started there.

I don’t know how many USB cables (or pieces of USB cables) I have sitting around. Some came with phones, tablets, or other devices… some were bought separately… some looked good… some looked cheap. I started going through the cables to see what kind of voltage drop there was when there was a Pi 4 on the end (with a micro-USB to USB-C adapter).

None of them ran the Pi without triggering the low voltage warning, and some of them couldn’t run the Pi without triggering the voltage warning even when idle. Two of them were so bad that the Pi couldn’t finish booting. The voltage drop across the cables was as much as 0.62V!

With those results, I decided to make my own cable. Unfortunately, when I looked in my USB parts drawer, I only had micro-USB plugs and USB type A jacks.

Out came the snips and I started chopping up the cables, starting with the ones that looked the best. Turns out that how a cable looks doesn’t mean much when it comes to how heavy the wire inside it is.

Eventually I found one that had considerably heavier wire than what I’d seen up to that point, so I decided to use it instead of chopping up the rest of the cables. I cut it to 60cm, soldered on the plug end, and gave it a try.

It was a lot better, but the Pi was still reporting that there’d been a low voltage condition at some point. I cut the cable to 50cm.

Then 40cm.

Then 30cm.

Then 20cm.

20cm did the trick, and I couldn’t trigger the low voltage warning anymore, even with the SDR plugged in and running and the CPU pinned to 100% (I usually use cat /dev/urandom > gzip > /dev/null for that).

Here it is, the beautiful and reliable USB cable of portable GQRXing:

Yeah, that’s hot glue. Works well and it’s strong but doesn’t look all that great…

Since I only had the micro-USB plugs on hand, I still have to use the adapter, which could also be wasting a bit of power. I need to order some other stuff sometime soon so I may grab a couple of parts to make another good cable or two.

To test the cable and battery pack, I hooked it up to my SDR Pi, fired up GQRX, told it to record the audio, and checked in on it every half hour. It ran for six hours before the battery LEDs showed it was at less than 25% capacity. I don’t like running those packs flat so I stopped the test there.

Before I shut down the Pi, I hopped onto it (using VNC on my phone, heh) and checked whether any of the warning conditions had been triggered (voltage, temperature, etc). Here’s what I saw:

0x0, or no problems at all… after running for six hours straight. Not too shabby!

This Is Why They Talk About Drying Your Filament

I went to start up a print today and loaded an old half-full spool of black PETG into the printer. I ran the filament through the nozzle to purge what was left of the previous filament and, as the white plastic faded to grey and then black, I heard an odd ticking sound coming from the nozzle.

I store my filament in zipper bags with a pack or two of desiccant, but even with those precautions, it only slows moisture down – it doesn’t stop it. It’ll make its way in through any tiny hole in the plastic, and water molecules can slowly make their way between the molecules of the plastic bag. You can’t see it or feel, it but with enough time and the right conditions, it’s enough to saturate the desiccant and start working its way into the filament.

In this case, the bag containing the filament spool had been sitting long enough and had gone through enough temperature/moisture cycles (I store it in the basement) that the filament had absorbed some moisture. The moisture was evaporating and creating bubbles and little pops in the plastic as it went through the nozzle at about 220° Celsius:

Bubbled Filament
You can easily see and feel the bubbles even though the diameter of the filament is only 1.75mm.

If I really wanted to, I could probably still print with it, but the printed surface will probably be rough and adhesion wouldn’t be as good.

Fortunately, drying filament is pretty simple. Machines dedicated to drying filament are available, and while they have trays and covers made to fit filament spools, I found them to be a bit too expensive for my budget. I ended up buying a cheap food dehydrator from my local hardware store and drilling a couple of holes in an old Tupperware container to use as a lid:

Now I just need to let it sit for a while and the filament will be good to go!

GQRX On The Raspberry Pi 4

I’ve been playing with SDRs on the Raspberry Pi 4 for almost a month now and I am happy to say that the new Pi (at least the 2GB model) has enough oomph to run GQRX with a Great Scott Gadgets HackRF One (at 4MSPS max), and a NooElec NESDR SMArt. I was SO happy to say it, I spent several hours writing up a howto, just for everything to fall apart at the second last step.

So… here’s a short version. If I get enough questions about it, I’ll look at salvaging what I still have and writing it up in detail again.

To get GQRX working on the Raspberry Pi 4B (the 2GB is the only version I have), you will need the following:

  • A Raspberry Pi 4B (I only tested with the 2GB version but I expect it will work fine with both the 1GB and 4GB versions)
  • An 8GB Class 10 (or larger/faster) microSD card
  • Internet connectivity through a wired Ethernet port
  • An Ethernet cable
  • An SDR (tested with the HackRF One and the NESDR SMArt)
  • An antenna that fits your SDR
  • A USB cable that fits your SDR (if necessary)
  • Headphones or a set of speakers with a 3.5mm plug
  • A heatsink and/or fan for the Pi (it requires so little cooling that you can just point a desk fan in its general direction and it should be okay)

So, here’s how to do it:

  • Image the microSD card with the official Raspbian version with desktop but without the extra software. Get it from here.
    Get this version of Raspbian
  • Connect it to an Ethernet port and power it up, then find it on your network and do the usual password/configuration/update steps.
  • Set the resolution to 800×600.
  • Force the audio output to the headphone jack.
  • Enable VNC.
  • Install GQRX from the respository (sudo apt install gqrx-sdr).
  • Connect to the Pi via VNC and turn the system volume down.
  • Connect your SDR (with antenna)
  • Run GQRX. If you’re having trouble or for information on settings, etc, check here for information.
  • In the “FFT” tab, change the
  • Turn up the system volume and/or software or hardware amplifiers in GQRX and your SDR until you can comfortably hear a signal.

And that’s about it.

I found, though, that I wanted to make the Pi a little more portable, and when using the Ethernet jack there seems to be a bit more noise in the GQRX display. Here’s what I did:

  • Install RaspAP, information and installation instructions are here.
  • Set up the Pi to be a wireless access point on a separate network from your Ethernet port.
  • Once the AP is running, disconnect the Pi from the Ethernet port and, using your computer, phone, or tablet, look for the SSID of the AP you set up and connect to it.
  • Once connected, run a VNC client (I use VNC Viewer by RealVNC but others should work as well).
  • I lowered the output power of the Pi’s wifi transmitter because I wanted to save as much power as possible, lower the amount of electrical noise the Pi generated, and keep the AP’s range as small as possible so as few people as possible can see it. To do that, add the following line to /etc/rc.local just before the “exit 0” line:
    iwconfig wlan0 txpower 5
    Change the value for txpower to whatever suits your needs (lower = lower transmitter power).
  • If you find you can’t connect to the AP or you want to change or update the Pi, you can always plug it back into the Ethernet port and connect to it that way.

Here’s what you’ll end up with (except with sound – my PC’s microphone isn’t working):

You can also ignore that last block of instructions and just hook the Pi up to an internal or HDMI-attached display. Some people find that using displays with resolutions of 800×600 or less cramps the GQRX display and makes navigation difficult. If you’re running VNC, you can set the resolution to whatever you want – just keep in mind that the Pi will start to sweat and lag if the display is too large.

If the Pi seems to be having trouble keeping up, try the following:

  • Make sure your Pi is adequately cooled and powered. Run vcgencmd get_throttled and if it shows any number other than 0x0, you have a temperature/power problem.
  • As mentioned above, lower the display resolution.
  • Remove the Raspbian desktop picture and replace it with a single colour.
  • In GQRX, one of the biggest CPU hogs is the main display. Go into the “FFT Settings” tab and lower the FFT Size and Rate. I use 8192 and 10fps on my Pi and that seems to work reasonably well.
  • Once you find the frequency you want to listen to, minimize GQRX. That should speed things up noticeably.
  • Lower GQRX’s sample rate by going into the “Configure I/O Devices” window (the little green PCI card icon) and lower the number. The HackRF in particular needs to be set lower than its 10MSPS default. 3-4MSPS for the HackRF and 2-3MSPS for the NESDR SMArt seems to do the trick.
  • Don’t run any extra services or applications on your Pi.
  • If you’re recording audio and it’s lagging or chirping, don’t record to the SD card – mount external USB storage (stick, drive, whatever) and use that instead.

The Pi – even the 4B – has its limitations. If you’re careful, though, you can pretty easily turn it into a small, portable, and powerful little SDR machine.

Software Defined Radio

On one of her visits a little while ago, Ms Geek brought over a box full of her hobby stuff for me to try if I was interested. One of the things in the box was a HackRF One Software Defined Radio (SDR). I had no idea devices like this existed, and we downloaded some software and she showed me how it worked. It’s… well, it’s a radio receiver (the HackRF One can also transmit!) that you connect to a computer by USB. If you’ve got the right software, the right drivers, and the right antenna, you can browse a good chunk of the radio spectrum and listen in to all kinds of neat stuff.

I tinkered with the HackRF for a while but didn’t have a lot of luck. One day, I found some old cable, soldered some BNC ends to it, and put the antenna outside.

What a difference – the whole thing came to life and I could hear (and thanks to the software, see) all kinds of stuff! Conversations between aircraft and the tower at the airport, weather reports, radio stations, what was wrong with city buses… all kinds of fascinating things.

Here’s the HackRF One, it’s roughly smartphone sized:

Not a great picture, it’s dark in here…

And what a neat machine it is! Radio and antennas are two things I know very little about, and while there’s a learning curve, it didn’t take too long before I was able to tell the difference between voice and data signals and use some of the software settings.

I figured that Ms Geek would probably want her SDR back at some point, so I figured I’d look into picking up one of my own. While the HackRF One is a really nice device, it cost more than what I’d hoped to spend, particularly since this is a brand new hobby.

Enter the NESDR SMArt:

Yep, still dark…

I found a bundle online for about 35 bucks that included the SDR, three antennas, and a magnetic antenna mount. The NESDR is a lot smaller than the HackRF One but it can’t listen to as much of the spectrum and can’t transmit. That’s okay though – I’m still just barely scratching the surface what what these devices can do.

I’ve been spending a lot of time browsing the airwaves and listening to various services or systems and trying to figure out what they are. Some are pretty easy, like the airport. They announce who they are with every transmission. Others, though, aren’t quite as easy to figure out, like who was whistling and then asking about a trailer of dirt, or where “home one” is. Then, there’s stuff like this:

What the hell is that? It whistles and every once in a while it changes pitch and frequency like in the picture. I have no idea what it is but I’m fascinated.

I’ve been playing with the SDR stuff every day since I moved that antenna outside, and every day I find something new and different. What a neat hobby!

It’s Here!

My order of Raspberry Pi 4s and a couple of doodads for them arrived today!

Had a bit of trouble with VNC, need to specifically enable it in raspi-config and change the resolution from the default, also in raspi-config (I’m using 1280×720). Since then, things have been going well. This board is FAST!

World’s Crappiest Oscilloscope… v1

When Ms Geek gave me an Arduino Leonardo to play with, one of the first things I did was go through the examples. After almost two decades of experience with PICs, I was amazed at how easy it was to get things like serial communication and ADC working. Don’t get me wrong – I’m still a PIC guy… but I think I’m an Arduino guy now, too.

The ReadAnalogVoltage example caught my attention because it was so simple. Here’s the setup. It’s just a potentiometer with one end terminal connected to +5v and one to GND, and the wiper connected to A0:

Not much to it, eh? That bent yellow wire in the middle just holds the Leonardo in place.

I played around with it for a while and watched the output on the Serial Plotter, but then I had a thought. You need to run the Arduino software to use the Serial Plotter, and besides, the Serial Plotter looks too nice. Half-remembered days of coaxing dusty old VT100 and TN3270 terminals back to life and running a BBS made me think – I could do the same thing, but not as good!

I dug through some of my old PIC programs and found a serial terminal that I wrote back in 2002. Between that and the ANSI sequences at, I stapled together a really bad looking display that I like to call the World’s Crappiest Oscilloscope, v1. Here’s the program:

// World's crappiest oscilloscope v1
// Borrows heavily from ReadAnalogVoltage example in the Arduino Examples menu
// Uses Arduino Leonardo, reads voltage on analog pin A0, then uses good old ANSI
// codes to
// draw a really bad oscilloscope in a serial terminal.
// A little amusing but very useless.
// Info about ANSI codes is at

void setup() {

  pinMode(A0, INPUT); // Set pin A0 to input.

  Serial.begin(9600); // initialize serial communication at 9600 bits per second.

  delay(3000);  // Should be enough time to start up a serial terminal.

  // Warm up the tubes...
  Serial.write(27); // Clear terminal screen with ESC [2J and ESC is ASCII 27
  Serial.println("Warming up the tubes, please wait...");
  delay(2000);  // This just here for dramatic effect.
  delay(2000);  // This also just here for dramatic effect.

void loop() {

  // Now set up the fancy oscilloscope screen. Ah, the good old ANSI days...

  // Set Oscilloscope screen to white markers on black background.
  Serial.write(27);  // Clear Terminal screen with (esc)[2J, (esc) is ASCII 27
                    // Serial.write sends binary data to the serial port
  Serial.write(27); // ESC again.
  Serial.print("[H"); // cursor to home.

  // The following lines draw the scale up the left side of the terminal screen and
  // the bottom border.
  Serial.print("0.00V|________________________________________________________________________________\r\n"); // 80x _
  Serial.print("                         WORLD'S CRAPPIEST OSCILLOSCOPE v1\r\n");

  byte ColumnCount = 7; // Okay, there are 50 columns to put data into, starting at column 7 and ending at 57.

  while (ColumnCount <= 87){
    int sensorValue = analogRead(A0); // read the input on analog pin 0. Need to use an int because it's a 10-bit number.
    float voltage = sensorValue * (5.0 / 1023.0); // Convert the reading (which goes from 0 - 1023) to a voltage (0 - 5V).

    int OscOut = (voltage * 4);  // so far so good but need to make it go the other way
    OscOut = 21 - OscOut;

    // now, staple everything together into one string to control the cursor
    // Control cursor position: ESC then [line;columnH
    String OscStr;
    OscStr = '[';
    OscStr = OscStr + OscOut;
    OscStr = OscStr + ';';
    OscStr = OscStr + ColumnCount;
    OscStr = OscStr + 'H';


    // Just for kicks, let's try to change the trace colour to green.



    ColumnCount = ColumnCount +1;
    delay(50); // wait a bit before going back so the screen doesn't fly by too quickly.


I really need to figure out how to widen the blocks in this theme… it kind of mangles the formatting. If you copy and paste it directly, it still works though. This is what it does (don’t start the video unless you have a strong heart – it’s THAT amazing):

I wonder if there actually were any of those old terminals set up with something like this back in the day…

It’s Not Lupus

I stumbled across this yesterday – it’s right out of the pilot episode of House M.D.:

Surgeons opened her skull to remove a cancer tumour – then they saw a tapeworm” –, June 7 2019

Disgusting, fascinating, and ultimately good news – the victim says her symptoms have gone away “almost 100 percent”.

Remember, folks – wash your hands and cook your pigs.

Fixed The Old Weather Station

I got a nice little weather station as a gift about a decade ago. It’s been pretty accurate and the display is usually nice and bright and colourful. Over the last while, however, the backlight has gone from bright, to flickering, to flashing once in a while, to completely dead. This made the unit almost useless unless it was daytime and you were standing right in front of it.

Today I cracked it open and gave fixing it a shot. It came apart pretty easily, but I learned later that with the problem I had that I didn’t need to remove the green circuit board. Removing it led to a lot of frustration and grief as it took me many tries to get everything lined up again.

Anyway, it turned out that there were two problems. One was that one of the wires wasn’t actually soldered to the backlight – there was a glob of solder and the wire was just resting against it. I thought that’d be an easy fix but unfortunately, it didn’t make any difference.

What I ended up doing was ignoring the original LED driver circuitry altogether and connected it to the power jack (tip positive). I put a two-pin female header in series to I could easily try different resistors:

1K was a little dim, 100 ohms was better, but I finally settled on 47 ohms. That made for about 110mA, well within a regular 1/4W resistor’s capacity, and considering there are four LEDs in parallel, that’s about 28mA per LED – nice and low. I’m pretty pleased with how it’s working at this point:

Nice and bright

Still, I’m going to run it for a few days to make sure that the resistor and backlight aren’t warming up before I solder the resistor in permanently and button the whole thing back up.

Hopefully this means I’ll get at least another ten years out of it.

Getting Two I2C Displays Working At Once On An Arduino

Ms Geek gave me an Arduino Leonardo a little while ago and from the moment she showed me how to get it to blink an LED, I’ve been hooked. I’ve been in the PIC camp for almost 20 years now, but the build environment and ease of use of the Arduino blew my mind and I’ve been tinkering with them every day since that little “L” LED blinked.

One of the things I wanted to do was get a display working. I played around with some of the old HD44780 LCDs that have been collecting a very thick coat of dust and they worked well enough, but something I’ve never done is use a graphic display. TFT displays were always expensive (and still kind of are), but nowadays there seems to be quite the selection of small OLED displays that are quite inexpensive.

I did some shopping around and found a deal on some 128×32 pixel displays as well as one 128×64 pixel display, both of which speak I2C. It was pretty easy getting them working with the Leonardo and the u8g2 library, and while you can fit a surprising amount of information on even a 128x32px display, I have some other ideas for other projects where it would be useful to have two displays working at the same time.

Here are the two displays I wanted to use. On the left is the 128x64px display that has a SH1106 controller, on the right is the 128x32px display that has an SSD1306 controller. Both are 5V tolerant, so they’re easy to connect to the Leonardo. The origin is the same on both – at the top left of the display.

One of the nice things about I2C is that you can select individual devices by address. No extra wires needed, just send the right signals down the wires and you’re talking to whichever device you’d like. The flexibility of addressing in I2C has its drawbacks, though. If you want to use multiple devices without any external circuitry, each device needs a different address.

Both of the displays came configured with the same address – 0x78 (or 0x30 if you’re treating it as a seven-bit address). The 128x32px display doesn’t seem to have any way to change the address, but by moving a tiny surface-mount resistor on the 128x64px display, I was able to change the address from 0x78(0x30) to 0x7A(0x3C):

Believe it or not, I’ve been soldering for 35 years and I’ve taken high-reliability soldering courses, but that was back in the day when my eyes still focused well, my hands didn’t shake, and the nerves in my right arm were still working properly. Hooo boy it was pretty frustrating to move that resistor over. On this display it was 4k7, next time I may just use a 1/4 watt resistor instead of the SMD. Regardless, my crappy soldering was good enough to change the address of the display.

Hooking everything up was easy. The Leonardo has breakout pins for hardware SDA and SCL lines, but I have some Pro Micro and Nanos that I’d like to use so I used the numbered digital pins instead (obviously, if you’re using something other than the Leonardo, you’ll need to check the pinout of your device for the right pins). In the Leonardo’s (and Pro Micro’s) case, the I2C pins are 2(SDA) and 3(SCL). It’s possible that 4k7 pullups might be needed on the SDA and SCL pins when using more than one device; in this case things seemed to work fine without them. Here it is, in all it’s connected glory:

I frequently leave the film protectors on stuff I buy. Makes me think that it’s still brand new, even when it’s not.

So, with two displays with different I2C addresses hooked up, I was able to get each one working individually just by changing the constructor and address. Getting both working at the same time took a little bit of work, but the Arduino Wire and u8g2 library reference pages and example programs had the information I needed. Here’s the program:

// Using two displays: the 128x64 SH1106 OLED (0x3C/0x78), and the 128x32 SSD1306
// (0x3D/0x7A).
// The 128x64 display will be DISPA, the 128x32 display will be DISPB.
// This program is a bit of a pig, using 60% of the program storage space and 95% of
// the dynamic memory.
// Sometimes when running this program, the Leonardo doesn't respond to serial port
// data/uploads. If that happens, start the compile/upload, immediately ground the
// RESET pin very briefly, and it should work.

// Need this to use the I2C bus. I2C pins on Leonardo are broken
// out but are also 2 (SDA) and 3 (SCL).
#include <Wire.h> 

// Need this to make displays do things and stuff.
#include <U8g2lib.h> 

// Select proper constructor (driver) for this particular 128x64 OLED display and
// call it DISPA. See for other
// drivers. There are lots of different OLED board configurations out there!
U8G2_SH1106_128X64_NONAME_F_HW_I2C DISPA(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Select constructor for this particular 128x32 OLED display, call it DISPB.                                                                               

// Set aliases for the I2C pins. They're broken out on the Leonardo but I'm using
// the numbered pins so it's seamless with other boards like the Pro Micro.
#define SDA 2  
#define SCL 3

void setup() {
  // put your setup code here, to run once:

  // Setting the pins that control the displays to all outputs. There are no inputs
  // on these two OLED displays to worry about - others may be different!
  pinMode(SDA, OUTPUT);  
  pinMode(SCL, OUTPUT);

  // Set I2C bus speed on Arduino and both displays. This may not be necessary
  // but I put it in anyway - one less thing to troubleshoot if things don't work.

  // Some devices say they're 0x78/0x7A, but others may say they're 0x3C/0x3D. It's
  // like that because the address is 7 bits but some places (u8g2 included) pad it
  // out to 8 bits. Adding a 0 on the end multiplies the value by 2.
  // Most of the small OLED displays out there seem to be set to 0x3C(0x78). Some
  // can be changed, but not all of them.
  // See for details.
  // Fire up the displays and get them ready to accept data.
  // Remember, DISPA is the 128x64px OLED, DISPB is the 128x32px OLED.                           

  // Select a font to use on DISPA and DISPB. They don't have to be the same, and
  // you can change them throughout the program, too. 
  // Check for others, there are LOTS.
  DISPA.setFont(u8g2_font_logisoso30_tf );
  DISPB.setFont(u8g2_font_logisoso30_tf );

  // Let's put some writing on DISPA. Make sure the display buffer is clear before
  // writing or drawing anything.

  // Move the starting position of what will be written/drawn next to x=0, y=32.
  // As shown in the above picture, coordinates start at 0,0 at the top left.
  // If you want to properly display text, make sure you set the y-value to at least
  // as large as how many pixels tall your font is.
  // If your display shows nothing, make sure you have set the y-value or everything
  // will end up being drawn beyond the edges of the display...
  DISPA.setCursor(0, 32); 
  // This just puts Howdy! in the selected font in the buffer. Nothing gets written
  // to the screen yet. You could move the cursor position again and write more text
  // to the buffer or draw some shapes if you wanted. At this point you're just
  // setting bits that will turn on the associated pixels.
  // See to find out how to
  // draw shapes and lines or even set individual pixels.

  // Take whatever's been written or drawn in the buffer and send it to the display.

  // Now, do the same thing for DISPB.
  DISPB.setCursor(0, 31);

  delay(2000);  // Wait two seconds to admire the displays before moving on.


void loop() {
  // put your main code here, to run repeatedly:

  // All this code does is say "HELLO" and show a count up on DISPA, while 
  // counting down on DISPB.

  byte CountUp = 0;
  while (CountUp <= 255) {
    DISPA.setCursor(0, 31);
    DISPA.setCursor(40, 63);

    DISPB.setCursor(40, 31);
    DISPB.print(255 - CountUp);
    CountUp = CountUp + 1;
  delay(500);  // Wait 500ms and do it again.

Here’s what it looks like when it’s running:

I am not a programmer, but there’s really not all that much to this particular project. Like I mention in the code, sometimes when the Leonardo is running this program, the Arduino programmer won’t be able to connect with the board. My guess is that it’s because almost all of the memory is used up, but I’m not sure. Anyway, what you need to do is start the compile/upload, immediately ground the RESET pin briefly (a quick tap will do), and watch the screen. Sometimes I have to do it more than once, but don’t panic if your board isn’t responding – it’s not dead.

I’ve only tried this on the Leonardo and the Pro Micro, both of which use the ATmega32u4 MCU.