Arduino, ESP32 and 3 hardware serial ports

When working with ESP32 WiFi/Bluetooth MCU under Arduino SDK for ESP32, you will notice that Serial work just fine. But Serial1 and Serial2 do not. ESP32 has 3 hardware UARTs that can be mapped to almost any pin. But, Serial1 and Serial2 will not work. In case of ESP32 this just has to be done in a slightly different way:

The trick is to use HardwareSerial library to access UART 1 and 2 instead of Serial1 and Serial2

ESP32 WiFi bluetooth development board

  • Class HardwareSerial accepts one parameter in constructor, it is a number of UART. Values from 0 (UART 1) to 2 (UART 3)
  • HardwareSerial(0) is the same as Serial so be aware
  • begin method accepts 4 parameters
    • baud speed
    • UART mode
    • RX pin
    • TX pin
      The real beauty of this solution is that almost any pin can be used as TX or RX pin for any UART. Most ESP32 dev boards have labels like TX2 or RX2, but you really do not have to exactly those pins. Every other GPIO pin can act as Serial RX, but only the ones between GPIO0 and GPIO31 can be used as TX. Still, that gives plenty of pins to choose from…

More about ESP32 can be read in Getting Started With ESP32 and Arduino post.

Crossbow LRS, hardware

Weather outside is bitchy. Period. It rains, then it's windy and then maybe there is some direct sunlight for 15 minutes. No way to fly or test my DIY RC radio link.

Weather is bitchy

But, there is some progress after all. My latest changes seems to be working just fine. On a bench link was stable for almost 3 hours. Later I too it for a standard range test: 2.8km LOS. It also worked, I still had around 5dB of link budget left on a ground level.

Back to the topic. Crossbow LRS is open source and open hardware. Maybe open hardware is too much, since there is almost no hardware to build. After all, first iteration is based on LoRa32u4 II development boards and running good old Arduino.

RX module requires no additional hardware:

Crossbow LRS receiver module

TX module is slightly more complex. It required voltage stabilizer and inverter/level shifter made with single 2N7000 FET transistor. I2C OLED display is an option:

Crossbow LRS transmitter module

A proper way of doing read callback receive with Arduino LoRa

Arduino LoRa is a great library that brings LoRa support (SX1276/SX1277/SX1278/SX1279) to Arduino world. I'm using it in my Crossbow LRS project (still not stable enough for flight, work in progress). Until now, the biggest problem with this library I've found is that examples suggests that heavy protocol processing inside interrupt callback is fine.

Unfortunately, it is not. It can lead to unexpected processing delays, create conflicts with other interrupts, bus clashes and other hard to debug things. This is why, the better way is to do packet reading (and processing) inside main loop and use read callback only to set a flag. Like this:

Only please remember to set all variables modified in ISR routine as volatile.

Hands on: LoRa32u4 II 868MHz LoRa development board

Idea for Crossbow, DIY LRS system did not appearned in my mind out of nowhere. All my previous LoRa attempts were aimed at telemetry purposes only. E45-TTL-100 are cool, but bulky. If I would want to use them, I would either have to attach Arduino to it or hack it open and reprogram onboard CPU (like Qczek LRS does). Somehow it was not something what suited me very much.

But then I came across Adafruit Feather LoRa32u4 RFM95. Awesome idea. ATmega32u4 and HopeRF RFM95 LoRa module on one PCB, Arduino compatible, reasonably small and light. As a bonus, can be LiPo battery operated and has own 1S LiPo chanrger. The only thing I did not liked (OK, not the only one, but that was the biggest one) was price tag: $34.95 is somehow slightly more than I'm willing to pay for ATmega32u4. Even with radio module. So, after some digging on eBay I've found something that looked like a clone of Adafruit Feather LoRa32u4 RFM95: BSFrance LoRa32u4 II.

LoRa32u4 II 868MHz LoRa development board

BSFrance LoRa32u4 II 868MHz LoRa development board

Read More

QuadMeUp Crossbow LRS: introduction

Few days ago I mentioned that I'm working on my own DIY long range radio system (LRS) that I named QuadMeUp Crossbow LRS. Today I will share some more details about it.

First of all, I'm not creating anything new or "amazing". There are plenty of "DIY" or OpenSource LRS systems. OpenLRS for example. Or QCZEK LRS that is made from almost nothing at all. And amazing commercial systems like TBS Crossfire.

Is there a place for something else? I think there is. For example, I was so pissed of by complexity of OpenLRS. So many options, so hard to understand. Or do you know how much micro RX for Crossfire costs? And that you do not need 2W of power to fly up to 5km? And most of pilots owning Crossfire never flied > 2km?

This is why, my idea for DIY LRS is:

Read More

Generate S.Bus with Arduino in a simple way

Did you noticed that lately I write about radios quite often? Well, I do and it’s not a coincidence. Proper introduction for what I’m working on will happen in a next few days, but now I will only write that this will be a mid-range, cheap, DIY radio link for UAVs. By mid-range I mean up to 5km. So, it will be positioned somewhere between 2.4GHz systems and full sale LRSes like DragonLink or TBS Crossfire.

Back to business. I’ve discovered, that there is very little in The Internet how to generate S.Bus with Arduino. OK, there are few libraries for reading Futaba S.Bus protocol like mikeshub/FUTABA_SBUS or zendes/SBUS but the only library made simple I’ve found is bolderflight/SBUS. Too bad it works only with Teensy devices. So, after a few hours of hard work, reading code of OpenTX, MultiWii, INAV, reading RcGroups and final help of Konstantin Sharlaimov (Digital Entity of INAV), I give you:

Generate S.Bus packets with Arduino in a simple way

But first, few simple facts:

Read More

E45-TTL-100 not transmitting when connected to Arduino

While working on one of my project involving Arduino and E45-TTL-100 LoRa 868MHz radio modules, I’ve discovered that it is not working exactly like expected. Documentation states:

(…) When the data inputted by user is up to 58 byte, the module will start wireless transmission (…)
(…) When the required transmission bytes is less than 58 byte, the module will wait 3-byte time and treat it as data termination (…)

If I understand this correctly, E45-TTL-100 should begin radio transmission when:

  • 58 bytes were sent via serial port
  • serial transmission stopped for 3 bytes. So, at 9600bps, 3ms pause whould trigger transmission
    void loop() {

In theory, code from the able should send string “Test” every 100ms. Unfortunately, it was not happening. Second E45-TTL-100 was not receiving anything. Also SDR dongle was not catching any transmissions. Something was wrong. I even contacted CD Ebyte, but they were unable to help me and The Internet was equally useless. What was wrong? No idea… looks like some kind of E45-TTL-100 MCU bug…

The solution

The solution is, hmmm, surprisingly simple. You not only have to stop transmitting, but also end serial port (Serial.end()) and open it again (Serial.begin()) after short period of time. In my experiments I’ve determined that 20-30ms of closed port selves the problem. So, code from above should be replaced with following:

void loop() {
        delay(70); //The rest of requested delay. So 100 - 30 = 70

It might not be the prettiest solution ever, but it works.

Testing 868MHz LoRa range, part 3: round trip

After determining that range of 868MHz LoRa wireless modules E45-TTL-100 have, at least, quite impressive range (5,7km and I was out of line-of-sight to test further) I’ve decided to test something else.

In the beginning I was planning to use those radio modules for telemetry only, but then another thought crossed my mind: why not to build DIY TBS Crossfire for the poor? After all, TBS Crossfire also uses 868MHz LoRa (SX1272 vs SX1276), so it should be possible to build DIY radio link for medium range (up to 5km) for RC planes, right?

First of all, I will need to know how fast data can be transferred and how much delay can I expect in real life. So I’ve modified Arduino code and E45-TTL-100 configuration:

  • UART speed bumped from 9600bps to 57600bps
  • air speed bumped from 2400bps to 19200bps
  • output power lowered from 100mW to 50mW (17dBm)
  • transmitter sends 5 bytes of data (current microseconds and prefix)
  • relay receives packet and resends it to transmitter
  • current received number is deducted from current microseconds and round trip time is showed on OLED display

LoRa E45-TTL-100 round trip test


  • Round trip time is 82ms on average and it does not changes with distance
  • at lower output power (50mW vs 100mW) reception at 2.8km is worse. 100% of packets are received only then antenna alignment is not worse than 45 degrees
  • with slightly bigger payload size (up to 7 bytes) it should be possible to archive at least 20Hz update rate

Project “Dropship glider” – introduction

When I saw this video from rctestflight I knew I will build something like that for myself. A voila, few months later it is done. Here is Dropship Glider.

Dropship glider - depron FPV delta glider

It is 29cm long with 20cm wingspan. Weights 97g AUW and has 21g/dm^2 wing loading. So, in theory, should glide. Somehow… If I got center of gravity right. And did not made ailerons too big. Or…

Dropship glider - depron FPV delta glider

Delta 6mm Depron “wing” is attached to 6mm carbon fiber rod and has some quite big dihedral: 15 degrees.

Dropship glider - depron FPV delta glider

The biggest problem was radio link and mixer for ailerons. I could not use my Taranis: I need that for a carrier and only radio control link I had was EM-16 with PPM output only and no way to setup any kind of mixer. The radio just has no “features” like that…

So, took one Arduino Pro Mini and wrote short program that acts as PPM decoder and mixer for ailerons.

Dropship glider - depron FPV delta glider Arduino

  • power is supplied by 1S LiPo taken from my Tiny Whoop
  • FPV AIO Eachine TX02 also taken from my Tine Whoop
  • 5V is supplied from cheap, regulated, step-up converter
  • 3rd servo is to release tether

First flight, or rather drop, tomorrow. There will be a video from the event of course…

How to read PPM signal with Arduino?

More than a year a published a post called Generate PPM signal with Arduino. Today it's time for part two: How to read PPM signal with Arduino?. Strange thing: internet does not gives very useful information on this topic. Strange, right? Some links to pages that does it either very very wrong or in not simple way.

There is a one almost good solution. It's an example code by Hasi123. Short, efficient and actaully works almost out of the box. But it has 2 problems:

  1. It is not a library. You have to copy paste code
  2. It alters Timer1 and that means, that many other things stops to work: PMW output, Servo library or anything else that uses Timer1. Crap…

So, I've invested some of my time and, based on that code, I've created Arduino library called PPMReader. Advantages?

  1. It is a library (!)
  2. It does not alters any timers (!)

Example code, that reads PPM signal connected to Pin 2 of Arduino Uno or Pro Mini (and other using ATmega328) and prints decoded channels over serial port would look like this:

#include "PPMReader.h"

// PPMReader(pin, interrupt)
PPMReader ppmReader(2, 0);

void setup()

void loop()
  static int count;
  while (ppmReader.get(count) != 0) { //print out the servo values
      Serial.print("  ");
  count = 0;

The only required configuration is a decission of a pin and interrupt. Not all pins have hardware interrupts, so on many boards this is limited to:

  • Arduino Uno, Pro Mini and other based on ATmega328: pin 2 / interrupt 0 or pin 3 / interrupt 1
  • Arduino Pro Micro and other based on ATmega32u4: pin 3 / interrupt 0, pin 2 / interrupt 1, pin 0 / interrupt 1, pin 1 / interrupt 3, pin 7 / interrupt 4

PPMReader Arduino library can be downloaded from GitHub.